From a3b32819b1578a261c1cc40cc384c8af3ed8fb0f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 22 Nov 2022 22:26:16 +0100 Subject: [PATCH] event/Loop: split InjectBreak() from Break() --- src/event/Loop.cxx | 17 ++++++----------- src/event/Loop.hxx | 31 ++++++++++++++++++++++++++----- src/event/Thread.cxx | 2 +- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index 5a83ba9a6..a405be240 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -87,17 +87,6 @@ EventLoop::GetUring() noexcept #endif -void -EventLoop::Break() noexcept -{ - if (quit.exchange(true)) - return; - -#ifdef HAVE_THREADED_EVENT_LOOP - wake_fd.Write(); -#endif -} - bool EventLoop::AddFD(int fd, unsigned events, SocketEvent &event) noexcept { @@ -286,6 +275,7 @@ EventLoop::Run() noexcept assert(IsInside()); assert(!quit); + assert(!quit_injected); #ifdef HAVE_THREADED_EVENT_LOOP assert(alive); assert(busy); @@ -437,6 +427,11 @@ EventLoop::OnSocketReady([[maybe_unused]] unsigned flags) noexcept wake_fd.Read(); + if (quit_injected) { + Break(); + return; + } + const std::scoped_lock lock(mutex); HandleInject(); } diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index 8e621872b..7aad5ac78 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -115,7 +115,7 @@ class EventLoop final bool alive; #endif - std::atomic_bool quit{false}; + bool quit = false; /** * True when the object has been modified and another check is @@ -124,6 +124,8 @@ class EventLoop final bool again; #ifdef HAVE_THREADED_EVENT_LOOP + bool quit_injected = false; + /** * True when handling callbacks, false when waiting for I/O or * timeout. @@ -187,11 +189,30 @@ public: #endif /** - * Stop execution of this #EventLoop at the next chance. This - * method is thread-safe and non-blocking: after returning, it - * is not guaranteed that the EventLoop has really stopped. + * Stop execution of this #EventLoop at the next chance. + * + * This method is not thread-safe. For stopping the + * #EventLoop from within another thread, use InjectBreak(). */ - void Break() noexcept; + void Break() noexcept { + quit = true; + } + +#ifdef HAVE_THREADED_EVENT_LOOP + /** + * Like Break(), but thread-safe. It is also non-blocking: + * after returning, it is not guaranteed that the EventLoop + * has really stopped. + */ + void InjectBreak() noexcept { + { + const std::scoped_lock lock{mutex}; + quit_injected = true; + } + + wake_fd.Write(); + } +#endif // HAVE_THREADED_EVENT_LOOP bool AddFD(int fd, unsigned events, SocketEvent &event) noexcept; bool ModifyFD(int fd, unsigned events, SocketEvent &event) noexcept; diff --git a/src/event/Thread.cxx b/src/event/Thread.cxx index e15fedfcc..7d1d43704 100644 --- a/src/event/Thread.cxx +++ b/src/event/Thread.cxx @@ -45,7 +45,7 @@ EventThread::Stop() noexcept assert(event_loop.IsAlive()); event_loop.SetAlive(false); - event_loop.Break(); + event_loop.InjectBreak(); thread.Join(); } }