aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2019-08-07 06:54:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2019-08-07 06:54:09 +0200
commit0592557e49cc7d6a2da2b5d9f5aaaeefbfcf7248 (patch)
tree8c3fc5e85769d3ffd0a697d6bfb97d70d6d6cebf
parentc08b0ce638361a84d3648aacd4ffbd0da6c357d8 (diff)
Make deadlock detection loop more robust
-rw-r--r--libbuild2/scheduler.cxx28
-rw-r--r--libbuild2/scheduler.hxx7
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<DWORD> (duration_cast<milliseconds> (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<scheduler*> (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: