diff options
author | Max Kellermann <max@duempel.org> | 2009-01-01 18:22:11 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2009-01-01 18:22:11 +0100 |
commit | b3e2635ac1d6cb46ae5a41e4c9760127453e49db (patch) | |
tree | b3fe2592a7f40eea7c28a2f7a9f6e8b386d61b55 /src/event_pipe.c | |
parent | 22bb5a5856ff4c195a179610dfb3f09af3183467 (diff) | |
download | mpd-b3e2635ac1d6cb46ae5a41e4c9760127453e49db.tar.gz mpd-b3e2635ac1d6cb46ae5a41e4c9760127453e49db.tar.xz mpd-b3e2635ac1d6cb46ae5a41e4c9760127453e49db.zip |
event_pipe: added pipe_event enum and callbacks
Make the event_pipe (formerly main_notify) send/receive a set of
events, with a callback for each one.
The default event PIPE_EVENT_SIGNAL does not have a callback. It
is still there for waking up the main thread, when it is waiting for
the player thread.
Diffstat (limited to 'src/event_pipe.c')
-rw-r--r-- | src/event_pipe.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/src/event_pipe.c b/src/event_pipe.c index 6ae70565e..448903410 100644 --- a/src/event_pipe.c +++ b/src/event_pipe.c @@ -28,14 +28,45 @@ GThread *main_task; static int event_pipe[2]; +static GMutex *event_pipe_mutex; +static bool pipe_events[PIPE_EVENT_MAX]; +static event_pipe_callback_t event_pipe_callbacks[PIPE_EVENT_MAX]; -static void consume_pipe(void) +/** + * Invoke the callback for a certain event. + */ +static void +event_pipe_invoke(enum pipe_event event) +{ + assert((unsigned)event < PIPE_EVENT_MAX); + assert(event != PIPE_EVENT_SIGNAL); + assert(event_pipe_callbacks[event] != NULL); + + event_pipe_callbacks[event](); +} + +static bool consume_pipe(void) { char buffer[256]; ssize_t r = read(event_pipe[0], buffer, sizeof(buffer)); + bool events[PIPE_EVENT_MAX]; if (r < 0 && errno != EAGAIN && errno != EINTR) FATAL("error reading from pipe: %s\n", strerror(errno)); + + g_mutex_lock(event_pipe_mutex); + memcpy(events, pipe_events, sizeof(events)); + memset(pipe_events, 0, sizeof(pipe_events)); + g_mutex_unlock(event_pipe_mutex); + + for (unsigned i = 0; i < PIPE_EVENT_MAX; ++i) + if (i != PIPE_EVENT_SIGNAL && events[i]) + /* invoke the event handler; the SIGNAL event + has no handler, because it is handled by + the event_pipe_wait() caller */ + event_pipe_invoke(i); + + return events[PIPE_EVENT_SIGNAL]; } static gboolean @@ -44,7 +75,6 @@ main_notify_event(G_GNUC_UNUSED GIOChannel *source, G_GNUC_UNUSED gpointer data) { consume_pipe(); - main_notify_triggered(); return true; } @@ -63,22 +93,55 @@ void event_pipe_init(void) g_io_add_watch(channel, G_IO_IN, main_notify_event, NULL); g_io_channel_unref(channel); + event_pipe_mutex = g_mutex_new(); + main_task = g_thread_self(); } void event_pipe_deinit(void) { + g_mutex_free(event_pipe_mutex); + xclose(event_pipe[0]); xclose(event_pipe[1]); } -void event_pipe_signal(void) +void +event_pipe_register(enum pipe_event event, event_pipe_callback_t callback) { - ssize_t w = write(event_pipe[1], "", 1); + assert(event != PIPE_EVENT_SIGNAL); + assert((unsigned)event < PIPE_EVENT_MAX); + assert(event_pipe_callbacks[event] == NULL); + + event_pipe_callbacks[event] = callback; +} + +void event_pipe_emit(enum pipe_event event) +{ + ssize_t w; + + assert((unsigned)event < PIPE_EVENT_MAX); + + g_mutex_lock(event_pipe_mutex); + if (pipe_events[event]) { + /* already set: don't write */ + g_mutex_unlock(event_pipe_mutex); + return; + } + + pipe_events[event] = true; + g_mutex_unlock(event_pipe_mutex); + + w = write(event_pipe[1], "", 1); if (w < 0 && errno != EAGAIN && errno != EINTR) g_error("error writing to pipe: %s", strerror(errno)); } +void event_pipe_signal(void) +{ + event_pipe_emit(PIPE_EVENT_SIGNAL); +} + void event_pipe_wait(void) { consume_pipe(); |