Fix potential race in dispatcher wakeup

This commit is contained in:
Eelco Dolstra 2015-08-10 11:58:33 +02:00
parent 6a1c950e94
commit 593850b956
3 changed files with 22 additions and 8 deletions

View file

@ -36,11 +36,14 @@ void State::dispatcher()
/* Sleep until we're woken up (either because a runnable build /* Sleep until we're woken up (either because a runnable build
is added, or because a build finishes). */ is added, or because a build finishes). */
{ {
std::unique_lock<std::mutex> lock(dispatcherMutex); auto dispatcherWakeup_(dispatcherWakeup.lock());
if (!*dispatcherWakeup_) {
printMsg(lvlDebug, format("dispatcher sleeping for %1%s") % printMsg(lvlDebug, format("dispatcher sleeping for %1%s") %
std::chrono::duration_cast<std::chrono::seconds>(sleepUntil - std::chrono::system_clock::now()).count()); std::chrono::duration_cast<std::chrono::seconds>(sleepUntil - std::chrono::system_clock::now()).count());
dispatcherWakeup.wait_until(lock, sleepUntil); dispatcherWakeup_.wait_until(dispatcherWakeupCV, sleepUntil);
}
nrDispatcherWakeups++; nrDispatcherWakeups++;
*dispatcherWakeup_ = false;
} }
} }
@ -167,6 +170,9 @@ system_time State::doDispatch()
void State::wakeDispatcher() void State::wakeDispatcher()
{ {
{ std::lock_guard<std::mutex> lock(dispatcherMutex); } // barrier {
dispatcherWakeup.notify_one(); auto dispatcherWakeup_(dispatcherWakeup.lock());
*dispatcherWakeup_ = true;
}
dispatcherWakeupCV.notify_one();
} }

View file

@ -202,8 +202,8 @@ private:
Sync<Runnable> runnable; Sync<Runnable> runnable;
/* CV for waking up the dispatcher. */ /* CV for waking up the dispatcher. */
std::condition_variable dispatcherWakeup; Sync<bool> dispatcherWakeup;
std::mutex dispatcherMutex; std::condition_variable_any dispatcherWakeupCV;
/* PostgreSQL connection pool. */ /* PostgreSQL connection pool. */
Pool<Connection> dbPool; Pool<Connection> dbPool;

View file

@ -60,6 +60,14 @@ public:
assert(s); assert(s);
return cv.wait_for(s->mutex, duration, pred); return cv.wait_for(s->mutex, duration, pred);
} }
template<class Clock, class Duration>
std::cv_status wait_until(std::condition_variable_any & cv,
const std::chrono::time_point<Clock, Duration> & duration)
{
assert(s);
return cv.wait_until(s->mutex, duration);
}
}; };
Lock lock() { return Lock(this); } Lock lock() { return Lock(this); }