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:
+67
-4
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user