diff options
author | Max Kellermann <max@musicpd.org> | 2019-02-05 22:38:45 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2019-02-05 22:38:45 +0100 |
commit | 6c67408944d86e756bbce9e993f7b4847cb11caf (patch) | |
tree | 61696bb2dd3662d07f185b10c3d05f1f16113a61 /src/event | |
parent | 261a816b21ad58501f2345e1f925e1a541863b94 (diff) |
event/Loop: add flag `alive`
This replaces the old `dead` flag which was unreliable; it was `false`
if the EventThread was not yet started, which could cause deadlocks in
BlockingCall().
Diffstat (limited to 'src/event')
-rw-r--r-- | src/event/Call.cxx | 2 | ||||
-rw-r--r-- | src/event/Loop.cxx | 12 | ||||
-rw-r--r-- | src/event/Loop.hxx | 20 | ||||
-rw-r--r-- | src/event/Thread.cxx | 6 |
4 files changed, 28 insertions, 12 deletions
diff --git a/src/event/Call.cxx b/src/event/Call.cxx index b03381da7..218d7c312 100644 --- a/src/event/Call.cxx +++ b/src/event/Call.cxx @@ -80,7 +80,7 @@ private: void BlockingCall(EventLoop &loop, std::function<void()> &&f) { - if (loop.IsDead() || loop.IsInside()) { + if (!loop.IsAlive() || loop.IsInside()) { /* we're already inside the loop - we can simply call the function */ f(); diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index e0aae6fc4..644cacc39 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -25,7 +25,13 @@ EventLoop::EventLoop(ThreadId _thread) :SocketMonitor(*this), - quit(false), dead(false), + /* if this instance is hosted by an EventThread (no ThreadId + known yet) then we're not yet alive until the thread is + started; for the main EventLoop instance, we assume it's + already alive, because nobody but EventThread will call + SetAlive() */ + alive(!_thread.IsNull()), + quit(false), thread(_thread) { SocketMonitor::Open(SocketDescriptor(wake_fd.Get())); @@ -143,12 +149,11 @@ EventLoop::Run() noexcept assert(IsInside()); assert(!quit); - assert(!dead); + assert(alive); assert(busy); SocketMonitor::Schedule(SocketMonitor::READ); AtScopeExit(this) { - dead = true; SocketMonitor::Cancel(); }; @@ -215,7 +220,6 @@ EventLoop::Run() noexcept } while (!quit); #ifndef NDEBUG - assert(!dead); assert(busy); assert(thread.IsInside()); #endif diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index 80b479494..0a73f6c57 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -85,12 +85,15 @@ class EventLoop final : SocketMonitor std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - std::atomic_bool quit; - /** - * If this is true, then Run() has returned. + * Is this #EventLoop alive, i.e. can events be scheduled? + * This is used by BlockingCall() to determine whether + * schedule in the #EventThread or to call directly (if + * there's no #EventThread yet/anymore). */ - std::atomic_bool dead; + bool alive; + + std::atomic_bool quit; /** * True when the object has been modified and another check is @@ -207,9 +210,12 @@ private: bool OnSocketReady(unsigned flags) noexcept override; public: - gcc_pure - bool IsDead() const noexcept { - return dead; + void SetAlive(bool _alive) noexcept { + alive = _alive; + } + + bool IsAlive() const noexcept { + return alive; } /** diff --git a/src/event/Thread.cxx b/src/event/Thread.cxx index a54b1e880..0ce5a775d 100644 --- a/src/event/Thread.cxx +++ b/src/event/Thread.cxx @@ -26,8 +26,11 @@ void EventThread::Start() { + assert(!event_loop.IsAlive()); assert(!thread.IsDefined()); + event_loop.SetAlive(true); + thread.Start(); } @@ -35,6 +38,9 @@ void EventThread::Stop() noexcept { if (thread.IsDefined()) { + assert(event_loop.IsAlive()); + event_loop.SetAlive(false); + event_loop.Break(); thread.Join(); } |