summaryrefslogtreecommitdiff
path: root/src/unix_signal.c
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2011-10-20 08:48:36 +0200
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2011-10-20 08:54:57 +0200
commitb565b6950bbd689be453983e3940235003ffcc45 (patch)
tree81d56258be5371d2b5cdbb088adbceba499632b8 /src/unix_signal.c
parentaf293d4059ff1e0873d452d871d41b501ed1636a (diff)
downloadpa-sink-ctl-b565b6950bbd689be453983e3940235003ffcc45.tar.gz
pa-sink-ctl-b565b6950bbd689be453983e3940235003ffcc45.tar.bz2
pa-sink-ctl-b565b6950bbd689be453983e3940235003ffcc45.zip
g_unix_signal: Remove g_ prefix to not collide with glib
There is a g_unix_signal_new function in glib as well now, but that is only allowed to be used for SIGINT, SIGHUP and SIGTERM, so we have to stay with our own.
Diffstat (limited to 'src/unix_signal.c')
-rw-r--r--src/unix_signal.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/unix_signal.c b/src/unix_signal.c
new file mode 100644
index 0000000..7577051
--- /dev/null
+++ b/src/unix_signal.c
@@ -0,0 +1,136 @@
+#define _POSIX_SOURCE
+#include <signal.h>
+#include <glib.h>
+#include "unix_signal.h"
+
+static GPtrArray *signal_data = NULL;
+
+typedef struct _UnixSignalData {
+ guint source_id;
+ GMainContext *context;
+ gboolean triggered;
+ gint signum;
+} UnixSignalData;
+
+typedef struct _UnixSignalSource {
+ GSource source;
+ UnixSignalData *data;
+} UnixSignalSource;
+
+static inline UnixSignalData *
+unix_signal_data(guint index)
+{
+ return (UnixSignalData *) g_ptr_array_index(signal_data, index);
+}
+
+static void
+handler(gint signum)
+{
+ g_assert(signal_data != NULL);
+ for (guint i = 0; i < signal_data->len; ++i)
+ if (unix_signal_data(i)->signum == signum)
+ unix_signal_data(i)->triggered = TRUE;
+ sigaction(signum, &(struct sigaction){handler}, NULL);
+}
+
+static gboolean
+check(GSource *source)
+{
+ UnixSignalSource *signal_source = (UnixSignalSource *) source;
+
+ return signal_source->data->triggered;
+}
+
+static gboolean
+prepare(GSource *source, gint *timeout_)
+{
+ UnixSignalSource *signal_source = (UnixSignalSource*) source;
+
+ if (signal_source->data->context == NULL) {
+ g_main_context_ref(signal_source->data->context = g_source_get_context(source));
+ signal_source->data->source_id = g_source_get_id(source);
+ }
+
+ *timeout_ = -1;
+
+ return signal_source->data->triggered;
+}
+
+static gboolean
+dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ UnixSignalSource *signal_source = (UnixSignalSource *) source;
+
+ signal_source->data->triggered = FALSE;
+
+ return callback(user_data) ? TRUE : FALSE;
+}
+
+static void
+finalize(GSource *source)
+{
+ UnixSignalSource *signal_source = (UnixSignalSource*) source;
+
+ sigaction(signal_source->data->signum, &(struct sigaction){NULL}, NULL);
+ g_main_context_unref(signal_source->data->context);
+ g_ptr_array_remove_fast(signal_data, signal_source->data);
+ if (signal_data->len == 0)
+ signal_data = (GPtrArray*) g_ptr_array_free(signal_data, TRUE);
+ g_free(signal_source->data);
+
+}
+static GSourceFuncs SourceFuncs =
+{
+ .prepare = prepare,
+ .check = check,
+ .dispatch = dispatch,
+ .finalize = finalize,
+ .closure_callback = NULL, .closure_marshal = NULL
+};
+
+static void
+unix_signal_source_init(GSource *source, gint signum)
+{
+ UnixSignalSource *signal_source = (UnixSignalSource *) source;
+
+ signal_source->data = g_new(UnixSignalData, 1);
+ signal_source->data->triggered = FALSE;
+ signal_source->data->signum = signum;
+ signal_source->data->context = NULL;
+
+ if (signal_data == NULL)
+ signal_data = g_ptr_array_new();
+ g_ptr_array_add(signal_data, signal_source->data);
+}
+
+GSource *
+unix_signal_source_new(gint signum)
+{
+ GSource *source = g_source_new(&SourceFuncs, sizeof(UnixSignalSource));
+
+ unix_signal_source_init(source, signum);
+ sigaction(signum, &(struct sigaction){handler}, NULL);
+
+ return source;
+}
+
+guint
+unix_signal_add_full(gint priority, gint signum, GSourceFunc function, gpointer data, GDestroyNotify notify)
+{
+ g_return_val_if_fail(function != NULL, 0);
+ GSource *source = unix_signal_source_new(signum);
+ guint id;
+
+ if (priority != G_PRIORITY_DEFAULT)
+ g_source_set_priority (source, priority);
+ g_source_set_callback(source, function, data, notify);
+ id = g_source_attach(source, NULL);
+ g_source_unref(source);
+
+ return id;
+}
+
+guint unix_signal_add(gint signum, GSourceFunc function, gpointer data)
+{
+ return unix_signal_add_full(G_PRIORITY_DEFAULT, signum, function, data, NULL);
+}