Commit e2821a42 authored by Dominik Charousset's avatar Dominik Charousset

Fix potential deadlock in the thread-safe clock

This quickfix switches to a recursive mutex to avoid a deadlock caused
by repeated calls to the cancel functions from different actors but
within the same thread (caused by actors becoming unreachable).
parent c6d63bb7
...@@ -58,8 +58,8 @@ public: ...@@ -58,8 +58,8 @@ public:
void cancel_dispatch_loop(); void cancel_dispatch_loop();
private: private:
std::mutex mx_; std::recursive_mutex mx_;
std::condition_variable cv_; std::condition_variable_any cv_;
std::atomic<bool> done_; std::atomic<bool> done_;
}; };
......
...@@ -23,7 +23,7 @@ namespace detail { ...@@ -23,7 +23,7 @@ namespace detail {
namespace { namespace {
using guard_type = std::unique_lock<std::mutex>; using guard_type = std::unique_lock<std::recursive_mutex>;
} // namespace <anonymous> } // namespace <anonymous>
...@@ -110,6 +110,9 @@ void thread_safe_actor_clock::run_dispatch_loop() { ...@@ -110,6 +110,9 @@ void thread_safe_actor_clock::run_dispatch_loop() {
guard_type guard{mx_}; guard_type guard{mx_};
while (done_ == false) { while (done_ == false) {
// Wait for non-empty schedule. // Wait for non-empty schedule.
// Note: The thread calling run_dispatch_loop() is guaranteed not to lock
// the mutex recursively. Otherwise, cv_.wait() or cv_.wait_until()
// would be unsafe, because wait operations call unlock() only once.
if (schedule_.empty()) { if (schedule_.empty()) {
cv_.wait(guard); cv_.wait(guard);
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment