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();
// - 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)
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.
{
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);
}
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
boundTaskExiting(task);
stopTaskManager();
}
-#else
- freeCapability(&MainCapability);
#endif
}
void
freeScheduler( void )
{
+ freeCapabilities();
freeTaskManager();
if (n_capabilities != 1) {
stgFree(capabilities);