diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-26 09:14:37 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-26 09:14:37 +0200 |
commit | 4a2a3bd5033744c31377d31ca54be00622280a1b (patch) | |
tree | 616cc10d585dd40ab252f02b55ff44c694c18fb4 /libbuild2/scheduler.txx | |
parent | 75cedf46dba58e94b55678dc64bd4f77e23de5cd (diff) |
Add ability to request serialization from scheduler
In particular, this can be used to make sure no other recipe is being
executed in parallel with the caller.
Diffstat (limited to 'libbuild2/scheduler.txx')
-rw-r--r-- | libbuild2/scheduler.txx | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/libbuild2/scheduler.txx b/libbuild2/scheduler.txx index 460c4d4..87c9384 100644 --- a/libbuild2/scheduler.txx +++ b/libbuild2/scheduler.txx @@ -137,4 +137,42 @@ namespace build2 if (tc.fetch_sub (1, memory_order_release) - 1 <= t.start_count) s.resume (tc); // Resume waiters, if any. } + + template <typename L> + size_t scheduler:: + serialize (L& el) + { + if (max_active_ == 1) // Serial execution. + return 0; + + lock l (mutex_); + + if (active_ == 1) + active_ = max_active_; + else + { + // Wait until we are the only active thread. + // + el.unlock (); + + while (active_ != 1) + { + // While it would have been more efficient to implement this via the + // condition variable notifications, that logic is already twisted + // enough (and took a considerable time to debug). So for now we keep + // it simple and do sleep and re-check. Make the sleep external not to + // trip up the deadlock detection. + // + deactivate_impl (true /* external */, move (l)); + active_sleep (std::chrono::milliseconds (10)); + l = activate_impl (true /* external */, false /* collision */); + } + + active_ = max_active_; + l.unlock (); // Important: unlock before attempting to relock external! + el.lock (); + } + + return max_active_ - 1; + } } |