diff options
Diffstat (limited to 'libbuild2/scheduler.cxx')
-rw-r--r-- | libbuild2/scheduler.cxx | 37 |
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 |