diff options
author | Max Kellermann <max@duempel.org> | 2013-01-10 00:57:18 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-01-10 00:57:18 +0100 |
commit | 5c3c5066382a22b1bf19ebbcc320e222b6812bfb (patch) | |
tree | 482eb1db3aba5df012ea598db39a346993644360 | |
parent | ecd5eb02c5094d3160db9d92937f7011e172c254 (diff) | |
download | mpd-5c3c5066382a22b1bf19ebbcc320e222b6812bfb.tar.gz mpd-5c3c5066382a22b1bf19ebbcc320e222b6812bfb.tar.xz mpd-5c3c5066382a22b1bf19ebbcc320e222b6812bfb.zip |
GlobalEvents: lock-less operation using std::atomic
Use a bit field instead of a mutex-protected bool array.
-rw-r--r-- | src/GlobalEvents.cxx | 39 | ||||
-rw-r--r-- | src/GlobalEvents.hxx | 7 | ||||
-rw-r--r-- | src/SignalHandlers.cxx | 2 |
3 files changed, 9 insertions, 39 deletions
diff --git a/src/GlobalEvents.cxx b/src/GlobalEvents.cxx index a483e31b4..664803ca3 100644 --- a/src/GlobalEvents.cxx +++ b/src/GlobalEvents.cxx @@ -20,9 +20,10 @@ #include "config.h" #include "GlobalEvents.hxx" #include "event/WakeFD.hxx" -#include "thread/Mutex.hxx" #include "mpd_error.h" +#include <atomic> + #include <assert.h> #include <glib.h> #include <string.h> @@ -34,8 +35,7 @@ namespace GlobalEvents { static WakeFD wake_fd; static guint source_id; - static Mutex mutex; - static bool flags[MAX]; + static std::atomic_uint flags; static Handler handlers[MAX]; } @@ -59,15 +59,10 @@ GlobalEventCallback(G_GNUC_UNUSED GIOChannel *source, if (!GlobalEvents::wake_fd.Read()) return true; - bool events[GlobalEvents::MAX]; - GlobalEvents::mutex.lock(); - memcpy(events, GlobalEvents::flags, sizeof(events)); - memset(GlobalEvents::flags, 0, - sizeof(GlobalEvents::flags)); - GlobalEvents::mutex.unlock(); + const unsigned flags = GlobalEvents::flags.fetch_and(0); for (unsigned i = 0; i < GlobalEvents::MAX; ++i) - if (events[i]) + if (flags & (1u << i)) /* invoke the event handler */ InvokeGlobalEvent(GlobalEvents::Event(i)); @@ -113,25 +108,7 @@ GlobalEvents::Emit(Event event) { assert((unsigned)event < MAX); - mutex.lock(); - if (flags[event]) { - /* already set: don't write */ - mutex.unlock(); - return; - } - - flags[event] = true; - mutex.unlock(); - - wake_fd.Write(); -} - -void -GlobalEvents::FastEmit(Event event) -{ - assert((unsigned)event < MAX); - - flags[event] = true; - - wake_fd.Write(); + const unsigned mask = 1u << unsigned(event); + if ((GlobalEvents::flags.fetch_or(mask) & mask) == 0) + wake_fd.Write(); } diff --git a/src/GlobalEvents.hxx b/src/GlobalEvents.hxx index ee977936a..458e77d7b 100644 --- a/src/GlobalEvents.hxx +++ b/src/GlobalEvents.hxx @@ -58,13 +58,6 @@ namespace GlobalEvents { void Register(Event event, Handler handler); void Emit(Event event); - - /** - * Similar to event_pipe_emit(), but aimed for use in signal handlers: - * it doesn't lock the mutex, and doesn't log on error. That makes it - * potentially lossy, but for its intended use, that does not matter. - */ - void FastEmit(Event event); } #endif /* MAIN_NOTIFY_H */ diff --git a/src/SignalHandlers.cxx b/src/SignalHandlers.cxx index 331028bde..4fd7675ff 100644 --- a/src/SignalHandlers.cxx +++ b/src/SignalHandlers.cxx @@ -40,7 +40,7 @@ static void exit_signal_handler(G_GNUC_UNUSED int signum) static void reload_signal_handler(G_GNUC_UNUSED int signum) { - GlobalEvents::FastEmit(GlobalEvents::RELOAD); + GlobalEvents::Emit(GlobalEvents::RELOAD); } static void |