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