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.
This commit is contained in:
Max Kellermann
2009-01-01 18:22:11 +01:00
parent 22bb5a5856
commit b3e2635ac1
8 changed files with 114 additions and 27 deletions
+67 -4
View File
@@ -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();