aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/scheduler.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/scheduler.cxx')
-rw-r--r--libbuild2/scheduler.cxx37
1 files changed, 26 insertions, 11 deletions
diff --git a/libbuild2/scheduler.cxx b/libbuild2/scheduler.cxx
index 5027f90..69673e6 100644
--- a/libbuild2/scheduler.cxx
+++ b/libbuild2/scheduler.cxx
@@ -93,12 +93,15 @@ namespace build2
}
void scheduler::
- deactivate (bool external)
+ deactivate_impl (bool external, lock&& rl)
{
- if (max_active_ == 1) // Serial execution.
- return;
+ // Note: assume non-serial execution.
- lock l (mutex_);
+ // Note: increment progress before/after every wait.
+ //
+ progress_.fetch_add (1, memory_order_relaxed);
+
+ lock l (move (rl)); // Make sure unlocked on exception.
active_--;
waiting_++;
@@ -131,11 +134,14 @@ namespace build2
}
}
- void scheduler::
- activate (bool external, bool collision)
+ scheduler::lock scheduler::
+ activate_impl (bool external, bool collision)
{
- if (max_active_ == 1) // Serial execution.
- return;
+ // Note: assume non-serial execution.
+
+ // Note: increment progress before/after every wait.
+ //
+ progress_.fetch_add (1, memory_order_relaxed);
lock l (mutex_);
@@ -160,6 +166,8 @@ namespace build2
if (shutdown_)
throw_generic_error (ECANCELED);
+
+ return l;
}
void scheduler::
@@ -207,7 +215,10 @@ namespace build2
deallocate (size_t n)
{
if (max_active_ == 1) // Serial execution.
+ {
+ assert (n == 0);
return;
+ }
lock l (mutex_);
active_ -= n;
@@ -216,13 +227,15 @@ namespace build2
size_t scheduler::
suspend (size_t start_count, const atomic_count& task_count)
{
+ assert (max_active_ != 1); // Suspend during serial execution?
+
wait_slot& s (
wait_queue_[
hash<const atomic_count*> () (&task_count) % wait_queue_size_]);
// This thread is no longer active.
//
- deactivate (false /* external */);
+ deactivate_impl (false /* external */, lock (mutex_));
// Note that the task count is checked while holding the lock. We also
// have to notify while holding the lock (see resume()). The aim here
@@ -259,7 +272,7 @@ namespace build2
// This thread is no longer waiting.
//
- activate (false /* external */, collision);
+ activate_impl (false /* external */, collision);
return tc;
}
@@ -1048,7 +1061,9 @@ namespace build2
// Re-check active/external counts for good measure (in case we were
// spinning too fast).
//
- if (np == op && s.active_ == 0 && s.external_ == 0 && !s.shutdown_)
+ if (np == op &&
+ s.active_ == 0 && s.external_ == 0 && !s.shutdown_ &&
+ s.progress_.load (memory_order_consume) == op)
{
// Shutting things down cleanly is tricky: we could have handled it
// in the scheduler (e.g., by setting a flag and then waking