* 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 <bernie@develer.com>
- *
+ * Copyright 2004, 2008 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999, 2000, 2001 Bernie Innocenti <bernie@codewiz.org>
* -->
*
* \brief IPC signals implementation.
* timer_delayTickes().
*
* \version $Id$
- *
- * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Bernie Innocenti <bernie@codewiz.org>
*/
#include "signal.h"
#include <drv/timer.h>
#include <kern/proc.h>
#include <kern/proc_p.h>
-
+
#if CONFIG_KERN_SIGNALS
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 */
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 */
}
#endif /* CONFIG_KERN_SIGNALS */
-