Commit 5c3c5066 authored by Max Kellermann's avatar Max Kellermann

GlobalEvents: lock-less operation using std::atomic

Use a bit field instead of a mutex-protected bool array.
parent ecd5eb02
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
#include "config.h" #include "config.h"
#include "GlobalEvents.hxx" #include "GlobalEvents.hxx"
#include "event/WakeFD.hxx" #include "event/WakeFD.hxx"
#include "thread/Mutex.hxx"
#include "mpd_error.h" #include "mpd_error.h"
#include <atomic>
#include <assert.h> #include <assert.h>
#include <glib.h> #include <glib.h>
#include <string.h> #include <string.h>
...@@ -34,8 +35,7 @@ ...@@ -34,8 +35,7 @@
namespace GlobalEvents { namespace GlobalEvents {
static WakeFD wake_fd; static WakeFD wake_fd;
static guint source_id; static guint source_id;
static Mutex mutex; static std::atomic_uint flags;
static bool flags[MAX];
static Handler handlers[MAX]; static Handler handlers[MAX];
} }
...@@ -59,15 +59,10 @@ GlobalEventCallback(G_GNUC_UNUSED GIOChannel *source, ...@@ -59,15 +59,10 @@ GlobalEventCallback(G_GNUC_UNUSED GIOChannel *source,
if (!GlobalEvents::wake_fd.Read()) if (!GlobalEvents::wake_fd.Read())
return true; return true;
bool events[GlobalEvents::MAX]; const unsigned flags = GlobalEvents::flags.fetch_and(0);
GlobalEvents::mutex.lock();
memcpy(events, GlobalEvents::flags, sizeof(events));
memset(GlobalEvents::flags, 0,
sizeof(GlobalEvents::flags));
GlobalEvents::mutex.unlock();
for (unsigned i = 0; i < GlobalEvents::MAX; ++i) for (unsigned i = 0; i < GlobalEvents::MAX; ++i)
if (events[i]) if (flags & (1u << i))
/* invoke the event handler */ /* invoke the event handler */
InvokeGlobalEvent(GlobalEvents::Event(i)); InvokeGlobalEvent(GlobalEvents::Event(i));
...@@ -113,25 +108,7 @@ GlobalEvents::Emit(Event event) ...@@ -113,25 +108,7 @@ GlobalEvents::Emit(Event event)
{ {
assert((unsigned)event < MAX); assert((unsigned)event < MAX);
mutex.lock(); const unsigned mask = 1u << unsigned(event);
if (flags[event]) { if ((GlobalEvents::flags.fetch_or(mask) & mask) == 0)
/* already set: don't write */ wake_fd.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();
} }
...@@ -58,13 +58,6 @@ namespace GlobalEvents { ...@@ -58,13 +58,6 @@ namespace GlobalEvents {
void Register(Event event, Handler handler); void Register(Event event, Handler handler);
void Emit(Event event); 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 */ #endif /* MAIN_NOTIFY_H */
...@@ -40,7 +40,7 @@ static void exit_signal_handler(G_GNUC_UNUSED int signum) ...@@ -40,7 +40,7 @@ static void exit_signal_handler(G_GNUC_UNUSED int signum)
static void reload_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 static void
......
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