// ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);
}
+ yield:
scheduleYield(&cap,task);
if (emptyRunQueue(cap)) continue; // look for work again
#endif
debugTrace(DEBUG_sched,
"--<< thread %lu (%s) stopped: blocked",
(unsigned long)t->id, whatNext_strs[t->what_next]);
- continue;
+ goto yield;
}
#endif
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();
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))
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);