]> code.delx.au - pulseaudio/blobdiff - polyp/mainloop-signal.c
Merge Pierre's changes
[pulseaudio] / polyp / mainloop-signal.c
index 89f195ed328103680991969d27e8af924cd4e15b..432498a8612e1cbf5f81bcfb562ae8bf68df1b9a 100644 (file)
 #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"
 
 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);