From 0592557e49cc7d6a2da2b5d9f5aaaeefbfcf7248 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 7 Aug 2019 06:54:09 +0200 Subject: Make deadlock detection loop more robust --- libbuild2/scheduler.cxx | 28 +++++++++++++++++++--------- libbuild2/scheduler.hxx | 7 +++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/libbuild2/scheduler.cxx b/libbuild2/scheduler.cxx index bb56810..e008fd6 100644 --- a/libbuild2/scheduler.cxx +++ b/libbuild2/scheduler.cxx @@ -171,18 +171,21 @@ namespace build2 sleep (const duration& d) { deactivate (true /* external */); + active_sleep (d); + activate (true /* external */); + } - // MINGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep(). + void scheduler:: + active_sleep (const duration& d) + { + // MinGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep(). // #ifndef _WIN32 this_thread::sleep_for (d); #else using namespace chrono; - Sleep (static_cast (duration_cast (d).count ())); #endif - - activate (true /* external */); } size_t scheduler:: @@ -801,6 +804,8 @@ namespace build2 void* scheduler:: deadlock_monitor (void* d) { + using namespace chrono; + scheduler& s (*static_cast (d)); lock l (s.mutex_); @@ -825,17 +830,22 @@ namespace build2 size_t op (s.progress_.load (memory_order_relaxed)), np (op); l.unlock (); - for (size_t i (0); op == np && i != 10000; ++i) + for (size_t i (0), n (10000), m (9900); op == np && i != n; ++i) { - // We don't really need consume, but let's keep it to slow things - // down in case yield() is a noop. + // On the last few iterations sleep a bit instead of yielding (in + // case yield() is a noop; we use the consume order for the same + // reason). // - this_thread::yield (); + if (i < m) + this_thread::yield (); + else + active_sleep (1ms); + np = s.progress_.load (memory_order_consume); } l.lock (); - // Re-check active/external counts for good measure (maybe we are + // 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_) diff --git a/libbuild2/scheduler.hxx b/libbuild2/scheduler.hxx index 7ceb239..99b27c9 100644 --- a/libbuild2/scheduler.hxx +++ b/libbuild2/scheduler.hxx @@ -153,6 +153,13 @@ namespace build2 void sleep (const duration&); + // Sleep without deactivating the thread. Essentially a portable + // std::this_thread::sleep_for() implementation but only with the + // milliseconds precision on some platforms. + // + static void + active_sleep (const duration&); + // Startup and shutdown. // public: -- cgit v1.1