diff options
Diffstat (limited to 'polyp/mainloop-signal.c')
-rw-r--r-- | polyp/mainloop-signal.c | 92 |
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]); |