in rts/Capability.c [753:821]
void waitForCapability (Capability **pCap, Task *task)
{
#if !defined(THREADED_RTS)
MainCapability.running_task = task;
task->cap = &MainCapability;
*pCap = &MainCapability;
#else
uint32_t i;
Capability *cap = *pCap;
if (cap == NULL) {
if (task->preferred_capability != -1) {
cap = capabilities[task->preferred_capability %
enabled_capabilities];
} else {
// Try last_free_capability first
cap = last_free_capability[task->node];
if (cap->running_task) {
// Otherwise, search for a free capability on this node.
cap = NULL;
for (i = task->node; i < enabled_capabilities;
i += n_numa_nodes) {
// visits all the capabilities on this node, because
// cap[i]->node == i % n_numa_nodes
if (!capabilities[i]->running_task) {
cap = capabilities[i];
break;
}
}
if (cap == NULL) {
// Can't find a free one, use last_free_capability.
cap = last_free_capability[task->node];
}
}
}
// record the Capability as the one this Task is now assocated with.
task->cap = cap;
} else {
ASSERT(task->cap == cap);
}
debugTrace(DEBUG_sched, "returning; I want capability %d", cap->no);
ACQUIRE_LOCK(&cap->lock);
if (!cap->running_task) {
// It's free; just grab it
cap->running_task = task;
RELEASE_LOCK(&cap->lock);
} else {
newReturningTask(cap,task);
RELEASE_LOCK(&cap->lock);
cap = waitForReturnCapability(task);
}
#if defined(PROFILING)
cap->r.rCCCS = CCS_SYSTEM;
#endif
ASSERT_FULL_CAPABILITY_INVARIANTS(cap, task);
debugTrace(DEBUG_sched, "resuming capability %d", cap->no);
*pCap = cap;
#endif
}