aboutsummaryrefslogtreecommitdiff
path: root/build2/scheduler.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-02-03 07:41:33 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-02-13 12:42:41 +0200
commit0d3ce80a2f0cd8398225e7ef7a1abbe7e77a38fc (patch)
treeddc78f3db07d5ba2cbccde7b62e95df8be099bc0 /build2/scheduler.cxx
parent63f6a8256e3f9fb47cb941be63baa70e2be48d3b (diff)
Add support for waiting on other threads task counts in scheduler
Diffstat (limited to 'build2/scheduler.cxx')
-rw-r--r--build2/scheduler.cxx36
1 files changed, 25 insertions, 11 deletions
diff --git a/build2/scheduler.cxx b/build2/scheduler.cxx
index 47d38e4..c151847 100644
--- a/build2/scheduler.cxx
+++ b/build2/scheduler.cxx
@@ -18,17 +18,20 @@ namespace build2
// See if we can run some of our own tasks.
//
- task_queue& tq (*task_queue_); // Must have been set by async() or task
- // would have been 0.
-
- for (lock ql (tq.mutex); !tq.shutdown && !empty_back (tq); )
- pop_back (tq, ql);
-
- // Note that empty task queue doesn't automatically mean the task count
- // is zero (some might still be executing asynchronously).
+ // If we are waiting on someone else's task count then there migh still
+ // be no queue which is set by async().
//
- if (task_count == 0)
- return;
+ if (task_queue* tq = task_queue_)
+ {
+ for (lock ql (tq->mutex); !tq->shutdown && !empty_back (*tq); )
+ pop_back (*tq, ql);
+
+ // Note that empty task queue doesn't automatically mean the task count
+ // is zero (some might still be executing asynchronously).
+ //
+ if (task_count == 0)
+ return;
+ }
suspend (task_count);
}
@@ -66,7 +69,18 @@ namespace build2
bool collision;
{
lock l (s.mutex);
- collision = (s.waiters++ != 0);
+
+ // We have a collision if there is already a waiter for a different
+ // task count.
+ //
+ collision = (s.waiters++ != 0 && s.tcount != &tc);
+
+ // This is nuanced: we want to always have the task count of the last
+ // thread to join the queue. Otherwise, if threads are leaving and
+ // joining the queue simultaneously, we may end up with a task count of
+ // a thread group that is no longer waiting.
+ //
+ s.tcount = &tc;
// Since we use a mutex for synchronization, we can relax the atomic
// access.