BeRTOS
|
00001 00128 #include "signal.h" 00129 00130 #include "cfg/cfg_timer.h" 00131 #include <cfg/debug.h> 00132 #include <cfg/depend.h> 00133 00134 #include <cpu/irq.h> 00135 #include <kern/proc.h> 00136 #include <kern/proc_p.h> 00137 00138 00139 #if CONFIG_KERN_SIGNALS 00140 00141 // Check config dependencies 00142 CONFIG_DEPEND(CONFIG_KERN_SIGNALS, CONFIG_KERN); 00143 00144 sigmask_t sig_waitSignal(Signal *s, sigmask_t sigs) 00145 { 00146 sigmask_t result; 00147 00148 /* Sleeping with IRQs disabled or preemption forbidden is illegal */ 00149 IRQ_ASSERT_ENABLED(); 00150 ASSERT(proc_preemptAllowed()); 00151 00152 /* 00153 * This is subtle: there's a race condition where a concurrent process 00154 * or an interrupt may call sig_send()/sig_post() to set a bit in 00155 * Process.sig_recv just after we have checked for it, but before we've 00156 * set Process.sig_wait to let them know we want to be awaken. 00157 * 00158 * In this case, we'd deadlock with the signal bit already set and the 00159 * process never being reinserted into the ready list. 00160 */ 00161 IRQ_DISABLE; 00162 00163 /* Loop until we get at least one of the signals */ 00164 while (!(result = s->recv & sigs)) 00165 { 00166 /* 00167 * Tell "them" that we want to be awaken when any of these 00168 * signals arrives. 00169 */ 00170 s->wait = sigs; 00171 00172 /* Go to sleep and proc_switch() to another process. */ 00173 proc_switch(); 00174 /* 00175 * When we come back here, the wait mask must have been 00176 * cleared by someone through sig_send()/sig_post(), and at 00177 * least one of the signals we were expecting must have been 00178 * delivered to us. 00179 */ 00180 ASSERT(!s->wait); 00181 ASSERT(s->recv & sigs); 00182 } 00183 00184 /* Signals found: clear them and return */ 00185 s->recv &= ~sigs; 00186 00187 IRQ_ENABLE; 00188 return result; 00189 } 00190 00191 #if CONFIG_TIMER_EVENTS 00192 00193 #include <drv/timer.h> 00194 00195 sigmask_t sig_waitTimeoutSignal(Signal *s, sigmask_t sigs, ticks_t timeout, 00196 Hook func, iptr_t data) 00197 { 00198 Timer t; 00199 sigmask_t res; 00200 cpu_flags_t flags; 00201 00202 ASSERT(!sig_checkSignal(s, SIG_TIMEOUT)); 00203 ASSERT(!(sigs & SIG_TIMEOUT)); 00204 /* IRQ are needed to run timer */ 00205 ASSERT(IRQ_ENABLED()); 00206 00207 if (func) 00208 timer_setSoftint(&t, func, data); 00209 else 00210 timer_set_event_signal(&t, proc_current(), SIG_TIMEOUT); 00211 timer_setDelay(&t, timeout); 00212 timer_add(&t); 00213 res = sig_waitSignal(s, SIG_TIMEOUT | sigs); 00214 00215 IRQ_SAVE_DISABLE(flags); 00216 /* Remove timer if sigs occur before timer signal */ 00217 if (!(res & SIG_TIMEOUT) && !sig_checkSignal(s, SIG_TIMEOUT)) 00218 timer_abort(&t); 00219 IRQ_RESTORE(flags); 00220 return res; 00221 } 00222 00223 #endif // CONFIG_TIMER_EVENTS 00224 00225 INLINE void __sig_signal(Signal *s, Process *proc, sigmask_t sigs, bool wakeup) 00226 { 00227 cpu_flags_t flags; 00228 00229 IRQ_SAVE_DISABLE(flags); 00230 00231 /* Set the signals */ 00232 s->recv |= sigs; 00233 00234 /* Check if process needs to be awoken */ 00235 if (s->recv & s->wait) 00236 { 00237 ASSERT(proc != current_process); 00238 00239 s->wait = 0; 00240 if (wakeup) 00241 proc_wakeup(proc); 00242 else 00243 SCHED_ENQUEUE_HEAD(proc); 00244 } 00245 IRQ_RESTORE(flags); 00246 } 00247 00248 void sig_sendSignal(Signal *s, Process *proc, sigmask_t sigs) 00249 { 00250 ASSERT_USER_CONTEXT(); 00251 IRQ_ASSERT_ENABLED(); 00252 ASSERT(proc_preemptAllowed()); 00253 00254 __sig_signal(s, proc, sigs, true); 00255 } 00256 00257 void sig_postSignal(Signal *s, Process *proc, sigmask_t sigs) 00258 { 00259 __sig_signal(s, proc, sigs, false); 00260 } 00261 00262 #endif /* CONFIG_KERN_SIGNALS */