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.c92
1 files changed, 81 insertions, 11 deletions
diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c
index eb3f5ddc..432498a8 100644
--- a/polyp/mainloop-signal.c
+++ b/polyp/mainloop-signal.c
@@ -32,6 +32,10 @@
#include <unistd.h>
#include <fcntl.h>
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
#include "mainloop-signal.h"
#include "util.h"
#include "xmalloc.h"
@@ -53,19 +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]);
@@ -81,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;
}
@@ -104,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);
+#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]);