From 4a2a3bd5033744c31377d31ca54be00622280a1b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 26 Feb 2024 09:14:37 +0200 Subject: 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. --- libbuild2/scheduler.txx | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'libbuild2/scheduler.txx') 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 + 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; + } } -- cgit v1.1