summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2019-09-27 00:49:15 +0000
committerMoritz Angermann <moritz.angermann@gmail.com>2020-09-18 07:33:40 +0000
commit2d827886bbfbc6218084a35627292484695fff19 (patch)
treefb108ae52bac385b0c25278044e0d8b010e93934
parent1d9ac2fcf7f3a35e4ec6493cf3a1793f4c2710d5 (diff)
downloadhaskell-2d827886bbfbc6218084a35627292484695fff19.tar.gz
rts: Factor out logic to identify a good capability for running a task
Not only does this make the control flow a bit clearer but it also allows us to add a TSAN suppression on this logic, which requires (harmless) data races.
-rw-r--r--rts/Capability.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/rts/Capability.c b/rts/Capability.c
index 7f6d66a37d..ee29db9e84 100644
--- a/rts/Capability.c
+++ b/rts/Capability.c
@@ -740,6 +740,46 @@ static Capability * waitForReturnCapability (Task *task)
#endif /* THREADED_RTS */
+#if defined(THREADED_RTS)
+
+/* ----------------------------------------------------------------------------
+ * find_capability_for_task
+ *
+ * Given a Task, identify a reasonable Capability to run it on. We try to
+ * find an idle capability if possible.
+ *
+ * ------------------------------------------------------------------------- */
+
+static Capability * find_capability_for_task(const Task * task)
+{
+ if (task->preferred_capability != -1) {
+ // Does the task have a preferred capability? If so, use it
+ return capabilities[task->preferred_capability %
+ enabled_capabilities];
+ } else {
+ // Try last_free_capability first
+ Capability *cap = last_free_capability[task->node];
+ if (cap->running_task == NULL) {
+ return cap;
+ } else {
+ // The last_free_capability is already busy, search for a free
+ // capability on this node.
+ for (uint32_t 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) {
+ return capabilities[i];
+ }
+ }
+
+ // Can't find a free one, use last_free_capability.
+ return last_free_capability[task->node];
+ }
+ }
+}
+#endif /* THREADED_RTS */
+
/* ----------------------------------------------------------------------------
* waitForCapability (Capability **pCap, Task *task)
*
@@ -760,38 +800,13 @@ void waitForCapability (Capability **pCap, Task *task)
*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];
- }
- }
- }
+ cap = find_capability_for_task(task);
// record the Capability as the one this Task is now assocated with.
task->cap = cap;
-
} else {
ASSERT(task->cap == cap);
}