X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FSchedule.c;h=63e2e99f06811d21025caaba7bf63b987a515745;hb=63179a7b10069d8f69f5bceef27008c9c7fb0aa8;hp=e17c6534d667cc0475297ee5a02cce9265664c85;hpb=99df892cc9620fcc92747b79bba75dad8a1d295c;p=ghc-hetmet.git diff --git a/rts/Schedule.c b/rts/Schedule.c index e17c653..63e2e99 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -399,6 +399,7 @@ schedule (Capability *initialCapability, Task *task) // ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task); } + yield: scheduleYield(&cap,task); if (emptyRunQueue(cap)) continue; // look for work again #endif @@ -479,6 +480,7 @@ run_thread: ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task); ASSERT(t->cap == cap); + ASSERT(t->bound ? t->bound->cap == cap : 1); prev_what_next = t->what_next; @@ -564,7 +566,7 @@ run_thread: debugTrace(DEBUG_sched, "--<< thread %lu (%s) stopped: blocked", (unsigned long)t->id, whatNext_strs[t->what_next]); - continue; + goto yield; } #endif @@ -652,15 +654,9 @@ scheduleFindWork (Capability *cap) scheduleCheckBlockedThreads(cap); #if defined(THREADED_RTS) || defined(PARALLEL_HASKELL) - // Try to activate one of our own sparks if (emptyRunQueue(cap)) { scheduleActivateSpark(cap); } #endif -#if defined(THREADED_RTS) - // Try to steak work if we don't have any - if (emptyRunQueue(cap)) { stealWork(cap); } -#endif - #if defined(PARALLEL_HASKELL) // if messages have been buffered... scheduleSendPendingMessages(); @@ -704,7 +700,9 @@ shouldYieldCapability (Capability *cap, Task *task) // - we need to yield this Capability to someone else // (see shouldYieldCapability()) // -// The return value indicates whether +// Careful: the scheduler loop is quite delicate. Make sure you run +// the tests in testsuite/concurrent (all ways) after modifying this, +// and also check the benchmarks in nofib/parallel for regressions. static void scheduleYield (Capability **pcap, Task *task) @@ -712,7 +710,10 @@ scheduleYield (Capability **pcap, Task *task) Capability *cap = *pcap; // if we have work, and we don't need to give up the Capability, continue. - if (!emptyRunQueue(cap) && !shouldYieldCapability(cap,task)) + if (!shouldYieldCapability(cap,task) && + (!emptyRunQueue(cap) || + blackholes_need_checking || + sched_state >= SCHED_INTERRUPTING)) return; // otherwise yield (sleep), and keep yielding if necessary. @@ -932,8 +933,13 @@ scheduleCheckBlackHoles (Capability *cap) { ACQUIRE_LOCK(&sched_mutex); if ( blackholes_need_checking ) { - checkBlackHoles(cap); blackholes_need_checking = rtsFalse; + // important that we reset the flag *before* checking the + // blackhole queue, otherwise we could get deadlock. This + // happens as follows: we wake up a thread that + // immediately runs on another Capability, blocks on a + // blackhole, and then we reset the blackholes_need_checking flag. + checkBlackHoles(cap); } RELEASE_LOCK(&sched_mutex); } @@ -1061,30 +1067,10 @@ scheduleSendPendingMessages(void) static void scheduleActivateSpark(Capability *cap) { - StgClosure *spark; - -/* We only want to stay here if the run queue is empty and we want some - work. We try to turn a spark into a thread, and add it to the run - queue, from where it will be picked up in the next iteration of the - scheduler loop. -*/ - if (!emptyRunQueue(cap)) - /* In the threaded RTS, another task might have pushed a thread - on our run queue in the meantime ? But would need a lock.. */ - return; - - - // Really we should be using reclaimSpark() here, but - // experimentally it doesn't seem to perform as well as just - // stealing from our own spark pool: - // spark = reclaimSpark(cap->sparks); - spark = tryStealSpark(cap->sparks); // defined in Sparks.c - - if (spark != NULL) { - debugTrace(DEBUG_sched, - "turning spark of closure %p into a thread", - (StgClosure *)spark); - createSparkThread(cap,spark); // defined in Sparks.c + if (anySparks()) + { + createSparkThread(cap); + debugTrace(DEBUG_sched, "creating a spark thread"); } } #endif // PARALLEL_HASKELL || THREADED_RTS @@ -2112,14 +2098,13 @@ exitScheduler( boundTaskExiting(task); stopTaskManager(); } -#else - freeCapability(&MainCapability); #endif } void freeScheduler( void ) { + freeCapabilities(); freeTaskManager(); if (n_capabilities != 1) { stgFree(capabilities);