From: Simon Marlow Date: Mon, 13 Mar 2006 15:40:44 +0000 (+0000) Subject: fix a rather subtle SMP bug in anyWorkForMe() X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=commitdiff_plain;h=1120322bb5c72ac0f7e6b126240da8ebf14362c4 fix a rather subtle SMP bug in anyWorkForMe() --- diff --git a/ghc/rts/Capability.c b/ghc/rts/Capability.c index a4380e7..203ca9f 100644 --- a/ghc/rts/Capability.c +++ b/ghc/rts/Capability.c @@ -53,19 +53,23 @@ globalWorkToDo (void) STATIC_INLINE rtsBool anyWorkForMe( Capability *cap, Task *task ) { - // If the run queue is not empty, then we only wake up the guy who - // can run the thread at the head, even if there is some other - // reason for this task to run (eg. interrupted=rtsTrue). - if (!emptyRunQueue(cap)) { - if (cap->run_queue_hd->bound == NULL) { - return (task->tso == NULL); - } else { - return (cap->run_queue_hd->bound == task); - } - } else if (task->tso == NULL && !emptySparkPoolCap(cap)) { - return rtsTrue; + if (task->tso != NULL) { + // A bound task only runs if its thread is on the run queue of + // the capability on which it was woken up. Otherwise, we + // can't be sure that we have the right capability: the thread + // might be woken up on some other capability, and task->cap + // could change under our feet. + return (!emptyRunQueue(cap) && cap->run_queue_hd->bound == task); + } else { + // A vanilla worker task runs if either (a) there is a + // lightweight thread at the head of the run queue, or (b) + // there are sparks to execute, or (c) there is some other + // global condition to check, such as threads blocked on + // blackholes. + return ((!emptyRunQueue(cap) && cap->run_queue_hd->bound == NULL) + || !emptySparkPoolCap(cap) + || globalWorkToDo()); } - return globalWorkToDo(); } #endif