BeRTOS
signal.c
Go to the documentation of this file.
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 */