X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fkern%2Fsignal.c;h=4333fa7937fe251a91ee2a0c5bdb1e4120d35006;hb=274910d36c7db1d556864384534f43c69d1bae19;hp=5abd7062679aeacd91f085741c18db31e71d29f8;hpb=791e167e053bdd9250d34a9a5ccae6ccde4d6679;p=bertos.git diff --git a/bertos/kern/signal.c b/bertos/kern/signal.c index 5abd7062..4333fa79 100644 --- a/bertos/kern/signal.c +++ b/bertos/kern/signal.c @@ -26,9 +26,8 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2004 Develer S.r.l. (http://www.develer.com/) - * Copyright 1999, 2000, 2001 Bernardo Innocenti - * + * Copyright 2004, 2008 Develer S.r.l. (http://www.develer.com/) + * Copyright 1999, 2000, 2001 Bernie Innocenti * --> * * \brief IPC signals implementation. @@ -96,8 +95,7 @@ * timer_delayTickes(). * * \version $Id$ - * - * \author Bernardo Innocenti + * \author Bernie Innocenti */ #include "signal.h" @@ -106,7 +104,7 @@ #include #include #include - + #if CONFIG_KERN_SIGNALS @@ -137,18 +135,45 @@ sigmask_t sig_wait(sigmask_t sigs) sigmask_t result; cpuflags_t flags; + /* + * This is subtle: there's a race condition where a concurrent + * process or an interrupt calls sig_signal() to set a bit in + * out sig_recv just after we have checked for it, but before + * we've set sig_wait to tell them we want to be awaken. + * + * In this case, we'd deadlock with the signal bit already + * set and the process never being reinserted into the ready + * list. + */ IRQ_SAVE_DISABLE(flags); /* Loop until we get at least one of the signals */ while (!(result = CurrentProcess->sig_recv & sigs)) { - /* go to sleep and proc_schedule() another process */ + /* + * Tell "them" that we want to be awaken when any of these + * signals arrives. + */ CurrentProcess->sig_wait = sigs; - proc_schedule(); - /* When we come back here, a signal must be arrived */ + /* + * Go to sleep and proc_schedule() another process. + * + * We re-enable IRQs because proc_schedule() does not + * guarantee to save and restore the interrupt mask. + */ + IRQ_RESTORE(flags); + proc_schedule(); + IRQ_SAVE_DISABLE(flags); + + /* + * When we come back here, the wait mask must have been + * cleared by someone through sig_signal(), and at least + * one of the signals we were expecting must have been + * delivered to us. + */ ASSERT(!CurrentProcess->sig_wait); - ASSERT(CurrentProcess->sig_recv); + ASSERT(CurrentProcess->sig_recv & sigs); } /* Signals found: clear them and return */ @@ -198,6 +223,8 @@ sigmask_t sig_waitTimeout(sigmask_t sigs, ticks_t timeout) void sig_signal(Process *proc, sigmask_t sigs) { cpuflags_t flags; + + /* See comment in sig_wait() for why this protection is necessary */ IRQ_SAVE_DISABLE(flags); /* Set the signals */ @@ -215,4 +242,3 @@ void sig_signal(Process *proc, sigmask_t sigs) } #endif /* CONFIG_KERN_SIGNALS */ -