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