aboutsummaryrefslogtreecommitdiff
path: root/src/event_pipe.c
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-01-01 18:22:11 +0100
committerMax Kellermann <max@duempel.org>2009-01-01 18:22:11 +0100
commitb3e2635ac1d6cb46ae5a41e4c9760127453e49db (patch)
treeb3fe2592a7f40eea7c28a2f7a9f6e8b386d61b55 /src/event_pipe.c
parent22bb5a5856ff4c195a179610dfb3f09af3183467 (diff)
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.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/src/event_pipe.c b/src/event_pipe.c
index 6ae70565..44890341 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();