signal.c

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