+ Task *task;
+
+ task = cap->running_task;
+
+ ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task);
+
+ cap->running_task = NULL;
+
+ // Check to see whether a worker thread can be given
+ // the go-ahead to return the result of an external call..
+ if (cap->returning_tasks_hd != NULL) {
+ giveCapabilityToTask(cap,cap->returning_tasks_hd);
+ // The Task pops itself from the queue (see waitForReturnCapability())
+ return;
+ }
+
+ // If the next thread on the run queue is a bound thread,
+ // give this Capability to the appropriate Task.
+ if (!emptyRunQueue(cap) && cap->run_queue_hd->bound) {
+ // Make sure we're not about to try to wake ourselves up
+ ASSERT(task != cap->run_queue_hd->bound);
+ task = cap->run_queue_hd->bound;
+ giveCapabilityToTask(cap,task);
+ return;
+ }
+
+ // 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 (cap->spare_workers) {
+ giveCapabilityToTask(cap,cap->spare_workers);
+ // The worker Task pops itself from the queue;
+ return;
+ }
+
+ // Create a worker thread if we don't have one. If the system
+ // 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_DEBUG(scheduler,
+ sched_belch("starting new worker on capability %d", cap->no));
+ startWorkerTask(cap, workerStart);
+ return;
+ }
+ }
+
+ last_free_capability = cap;
+ IF_DEBUG(scheduler, sched_belch("freeing capability %d", cap->no));
+}
+
+void
+releaseCapability (Capability* cap UNUSED_IF_NOT_THREADS)
+{
+ ACQUIRE_LOCK(&cap->lock);
+ releaseCapability_(cap);
+ RELEASE_LOCK(&cap->lock);
+}
+
+static void
+releaseCapabilityAndQueueWorker (Capability* cap UNUSED_IF_NOT_THREADS)
+{
+ Task *task;
+
+ ACQUIRE_LOCK(&cap->lock);
+
+ task = cap->running_task;
+
+ // If the current task is a worker, save it on the spare_workers
+ // list of this Capability. A worker can mark itself as stopped,
+ // in which case it is not replaced on the spare_worker queue.
+ // This happens when the system is shutting down (see
+ // Schedule.c:workerStart()).
+ // Also, be careful to check that this task hasn't just exited
+ // Haskell to do a foreign call (task->suspended_tso).
+ if (!isBoundTask(task) && !task->stopped && !task->suspended_tso) {
+ task->next = cap->spare_workers;
+ cap->spare_workers = task;
+ }
+ // Bound tasks just float around attached to their TSOs.
+
+ releaseCapability_(cap);
+
+ RELEASE_LOCK(&cap->lock);
+}
+#endif
+
+/* ----------------------------------------------------------------------------
+ * waitForReturnCapability( Task *task )
+ *
+ * Purpose: when an OS thread returns from an external call,
+ * it calls waitForReturnCapability() (via Schedule.resumeThread())
+ * to wait for permission to enter the RTS & communicate the
+ * result of the external call back to the Haskell thread that
+ * made it.
+ *
+ * ------------------------------------------------------------------------- */
+void
+waitForReturnCapability (Capability **pCap,
+ Task *task UNUSED_IF_NOT_THREADS)
+{
+#if !defined(THREADED_RTS)
+
+ MainCapability.running_task = task;
+ task->cap = &MainCapability;
+ *pCap = &MainCapability;
+