globalWorkToDo (void)
{
return blackholes_need_checking
- || interrupted
+ || sched_state >= SCHED_INTERRUPTING
;
}
#endif
// other global condition to check, such as threads blocked on
// blackholes).
if (emptyRunQueue(cap)) {
- return !emptySparkPoolCap(cap) || globalWorkToDo();
+ return !emptySparkPoolCap(cap)
+ || !emptyWakeupQueue(cap)
+ || globalWorkToDo();
} else
return cap->run_queue_hd->bound == NULL;
}
cap->suspended_ccalling_tasks = NULL;
cap->returning_tasks_hd = NULL;
cap->returning_tasks_tl = NULL;
+ cap->wakeup_queue_hd = END_TSO_QUEUE;
+ cap->wakeup_queue_tl = END_TSO_QUEUE;
#endif
cap->f.stgGCEnter1 = (F_)__stg_gc_enter_1;
// is interrupted, we only create a worker task if there
// are threads that need to be completed. If the system is
// shutting down, we never create a new worker.
- if (!shutting_down_scheduler) {
+ if (sched_state < SCHED_SHUTTING_DOWN || !emptyRunQueue(cap)) {
IF_DEBUG(scheduler,
sched_belch("starting new worker on capability %d", cap->no));
startWorkerTask(cap, workerStart);
// If we have an unbound thread on the run queue, or if there's
// anything else to do, give the Capability to a worker thread.
- if (!emptyRunQueue(cap) || !emptySparkPoolCap(cap) || globalWorkToDo()) {
+ if (!emptyRunQueue(cap) || !emptyWakeupQueue(cap)
+ || !emptySparkPoolCap(cap) || globalWorkToDo()) {
if (cap->spare_workers) {
giveCapabilityToTask(cap,cap->spare_workers);
// The worker Task pops itself from the queue;
}
/* ----------------------------------------------------------------------------
+ * Wake up a thread on a Capability.
+ *
+ * This is used when the current Task is running on a Capability and
+ * wishes to wake up a thread on a different Capability.
+ * ------------------------------------------------------------------------- */
+
+void
+wakeupThreadOnCapability (Capability *cap, StgTSO *tso)
+{
+ ASSERT(tso->cap == cap);
+ ASSERT(tso->bound ? tso->bound->cap == cap : 1);
+
+ ACQUIRE_LOCK(&cap->lock);
+ if (cap->running_task == NULL) {
+ // nobody is running this Capability, we can add our thread
+ // directly onto the run queue and start up a Task to run it.
+ appendToRunQueue(cap,tso);
+
+ // start it up
+ cap->running_task = myTask(); // precond for releaseCapability_()
+ releaseCapability_(cap);
+ } else {
+ appendToWakeupQueue(cap,tso);
+ // someone is running on this Capability, so it cannot be
+ // freed without first checking the wakeup queue (see
+ // releaseCapability_).
+ }
+ RELEASE_LOCK(&cap->lock);
+}
+
+/* ----------------------------------------------------------------------------
* prodCapabilities
*
* Used to indicate that the interrupted flag is now set, or some
{
nat i;
- ASSERT(interrupted && shutting_down_scheduler);
+ ASSERT(sched_state == SCHED_SHUTTING_DOWN);
task->cap = cap;