signal.c
Go to the documentation of this file.00001 00101 #include "signal.h" 00102 00103 #include "cfg/cfg_timer.h" 00104 #include <cfg/debug.h> 00105 #include <cfg/depend.h> 00106 00107 #include <cpu/irq.h> 00108 #include <kern/proc.h> 00109 #include <kern/proc_p.h> 00110 00111 00112 #if CONFIG_KERN_SIGNALS 00113 00114 // Check config dependencies 00115 CONFIG_DEPEND(CONFIG_KERN_SIGNALS, CONFIG_KERN); 00116 00122 sigmask_t sig_check(sigmask_t sigs) 00123 { 00124 sigmask_t result; 00125 cpu_flags_t flags; 00126 00127 IRQ_SAVE_DISABLE(flags); 00128 result = CurrentProcess->sig_recv & sigs; 00129 CurrentProcess->sig_recv &= ~sigs; 00130 IRQ_RESTORE(flags); 00131 00132 return result; 00133 } 00134 00135 00140 sigmask_t sig_wait(sigmask_t sigs) 00141 { 00142 sigmask_t result; 00143 cpu_flags_t flags; 00144 00145 /* Sleeping with IRQs disabled or preemption forbidden is illegal */ 00146 IRQ_ASSERT_ENABLED(); 00147 ASSERT(proc_allowed()); 00148 00149 /* 00150 * This is subtle: there's a race condition where a concurrent 00151 * process or an interrupt may call sig_signal() to set a bit in 00152 * Process.sig_recv just after we have checked for it, but before 00153 * we've set Process.sig_wait to let them know we want to be awaken. 00154 * 00155 * In this case, we'd deadlock with the signal bit already set 00156 * and the process never being reinserted into the ready list. 00157 */ 00158 // FIXME: just use IRQ_DISABLE() here 00159 IRQ_SAVE_DISABLE(flags); 00160 00161 /* Loop until we get at least one of the signals */ 00162 while (!(result = CurrentProcess->sig_recv & sigs)) 00163 { 00164 /* 00165 * Tell "them" that we want to be awaken when any of these 00166 * signals arrives. 00167 */ 00168 CurrentProcess->sig_wait = sigs; 00169 00170 /* 00171 * Go to sleep and proc_switch() to another process. 00172 * 00173 * We re-enable IRQs because proc_switch() does not 00174 * guarantee to save and restore the interrupt mask. 00175 */ 00176 IRQ_RESTORE(flags); 00177 proc_switch(); 00178 IRQ_SAVE_DISABLE(flags); 00179 00180 /* 00181 * When we come back here, the wait mask must have been 00182 * cleared by someone through sig_signal(), and at least 00183 * one of the signals we were expecting must have been 00184 * delivered to us. 00185 */ 00186 ASSERT(!CurrentProcess->sig_wait); 00187 ASSERT(CurrentProcess->sig_recv & sigs); 00188 } 00189 00190 /* Signals found: clear them and return */ 00191 CurrentProcess->sig_recv &= ~sigs; 00192 00193 IRQ_RESTORE(flags); 00194 return result; 00195 } 00196 00197 #if CONFIG_TIMER_EVENTS 00198 00199 #include <drv/timer.h> 00206 sigmask_t sig_waitTimeout(sigmask_t sigs, ticks_t timeout) 00207 { 00208 Timer t; 00209 sigmask_t res; 00210 cpu_flags_t flags; 00211 00212 ASSERT(!sig_check(SIG_TIMEOUT)); 00213 ASSERT(!(sigs & SIG_TIMEOUT)); 00214 /* IRQ are needed to run timer */ 00215 ASSERT(IRQ_ENABLED()); 00216 00217 timer_set_event_signal(&t, proc_current(), SIG_TIMEOUT); 00218 timer_setDelay(&t, timeout); 00219 timer_add(&t); 00220 res = sig_wait(SIG_TIMEOUT | sigs); 00221 00222 IRQ_SAVE_DISABLE(flags); 00223 /* Remove timer if sigs occur before timer signal */ 00224 if (!(res & SIG_TIMEOUT) && !sig_check(SIG_TIMEOUT)) 00225 timer_abort(&t); 00226 IRQ_RESTORE(flags); 00227 return res; 00228 } 00229 00230 #endif // CONFIG_TIMER_EVENTS 00231 00232 00239 void sig_signal(Process *proc, sigmask_t sigs) 00240 { 00241 cpu_flags_t flags; 00242 00243 /* See comment in sig_wait() for why this protection is necessary */ 00244 IRQ_SAVE_DISABLE(flags); 00245 00246 /* Set the signals */ 00247 proc->sig_recv |= sigs; 00248 00249 /* Check if process needs to be awoken */ 00250 if (proc->sig_recv & proc->sig_wait) 00251 { 00252 /* Wake up process and enqueue in ready list */ 00253 proc->sig_wait = 0; 00254 SCHED_ENQUEUE(proc); 00255 } 00256 00257 IRQ_RESTORE(flags); 00258 } 00259 00260 #endif /* CONFIG_KERN_SIGNALS */
