summaryrefslogtreecommitdiffstats
path: root/polyp/mainloop-signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'polyp/mainloop-signal.c')
-rw-r--r--polyp/mainloop-signal.c114
1 files changed, 102 insertions, 12 deletions
diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c
index 89f195ed..432498a8 100644
--- a/polyp/mainloop-signal.c
+++ b/polyp/mainloop-signal.c
@@ -30,6 +30,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
#include "mainloop-signal.h"
#include "util.h"
@@ -38,7 +43,11 @@
struct pa_signal_event {
int sig;
+#ifdef HAVE_SIGACTION
struct sigaction saved_sigaction;
+#else
+ void (*saved_handler)(int sig);
+#endif
void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata);
void *userdata;
void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata);
@@ -48,16 +57,70 @@ struct pa_signal_event {
static struct pa_mainloop_api *api = NULL;
static int signal_pipe[2] = { -1, -1 };
static struct pa_io_event* io_event = NULL;
+static struct pa_defer_event *defer_event = NULL;
static struct pa_signal_event *signals = NULL;
+#ifdef OS_IS_WIN32
+static unsigned int waiting_signals = 0;
+static CRITICAL_SECTION crit;
+#endif
+
static void signal_handler(int sig) {
+#ifndef HAVE_SIGACTION
+ signal(sig, signal_handler);
+#endif
write(signal_pipe[1], &sig, sizeof(sig));
+
+#ifdef OS_IS_WIN32
+ EnterCriticalSection(&crit);
+ waiting_signals++;
+ LeaveCriticalSection(&crit);
+#endif
+}
+
+static void dispatch(struct pa_mainloop_api*a, int sig) {
+ struct pa_signal_event*s;
+
+ for (s = signals; s; s = s->next)
+ if (s->sig == sig) {
+ assert(s->callback);
+ s->callback(a, s, sig, s->userdata);
+ break;
+ }
+}
+
+static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) {
+ ssize_t r;
+ int sig;
+ unsigned int sigs;
+
+#ifdef OS_IS_WIN32
+ EnterCriticalSection(&crit);
+ sigs = waiting_signals;
+ waiting_signals = 0;
+ LeaveCriticalSection(&crit);
+#endif
+
+ while (sigs) {
+ if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
+ pa_log(__FILE__": read(): %s\n", strerror(errno));
+ return;
+ }
+
+ if (r != sizeof(sig)) {
+ pa_log(__FILE__": short read()\n");
+ return;
+ }
+
+ dispatch(a, sig);
+
+ sigs--;
+ }
}
static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
ssize_t r;
int sig;
- struct pa_signal_event*s;
assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
@@ -73,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu
pa_log(__FILE__": short read()\n");
return;
}
-
- for (s = signals; s; s = s->next)
- if (s->sig == sig) {
- assert(s->callback);
- s->callback(a, s, sig, s->userdata);
- break;
- }
+
+ dispatch(a, sig);
}
int pa_signal_init(struct pa_mainloop_api *a) {
- assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event);
-
+ assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event);
+
+#ifdef OS_IS_WIN32
+ if (_pipe(signal_pipe, 200, _O_BINARY) < 0) {
+#else
if (pipe(signal_pipe) < 0) {
+#endif
pa_log(__FILE__": pipe() failed: %s\n", strerror(errno));
return -1;
}
@@ -96,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) {
pa_fd_set_cloexec(signal_pipe[1], 1);
api = a;
+
+#ifndef OS_IS_WIN32
io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
assert(io_event);
+#else
+ defer_event = api->defer_new(api, defer, NULL);
+ assert(defer_event);
+
+ InitializeCriticalSection(&crit);
+#endif
+
return 0;
}
void pa_signal_done(void) {
- assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event);
+ assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event));
while (signals)
pa_signal_free(signals);
- api->io_free(io_event);
+#ifndef OS_IS_WIN32
+ api->io_free(io_event);
io_event = NULL;
+#else
+ api->defer_free(defer_event);
+ defer_event = NULL;
+
+ DeleteCriticalSection(&crit);
+#endif
close(signal_pipe[0]);
close(signal_pipe[1]);
@@ -120,7 +198,11 @@ void pa_signal_done(void) {
struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) {
struct pa_signal_event *e = NULL;
+
+#ifdef HAVE_SIGACTION
struct sigaction sa;
+#endif
+
assert(sig > 0 && callback);
for (e = signals; e; e = e->next)
@@ -133,12 +215,16 @@ struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainl
e->userdata = userdata;
e->destroy_callback = NULL;
+#ifdef HAVE_SIGACTION
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
+#else
+ if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
+#endif
goto fail;
e->previous = NULL;
@@ -162,7 +248,11 @@ void pa_signal_free(struct pa_signal_event *e) {
else
signals = e->next;
+#ifdef HAVE_SIGACTION
sigaction(e->sig, &e->saved_sigaction, NULL);
+#else
+ signal(e->sig, e->saved_handler);
+#endif
if (e->destroy_callback)
e->destroy_callback(api, e, e->userdata);