]> git.cworth.org Git - apitrace/blobdiff - os_posix.cpp
Always write snappy chunk lengths in little endian.
[apitrace] / os_posix.cpp
index c072d5da7c4361a216d36e669fc652d6464e1c86..991ad0e7cabef3162162fd19176e2d0b6580c9d6 100644 (file)
@@ -24,6 +24,7 @@
  **************************************************************************/
 
 
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -138,82 +139,92 @@ Abort(void)
 }
 
 
-struct Interrupts
-{
-    Interrupts()
-        : set(false),
-          sig_int(NULL),
-          sig_hup(NULL),
-          sig_term(NULL),
-          sig_segv(NULL),
-          handler(NULL)
-    {}
-
-    bool set;
-    void (*sig_int)(int);
-    void (*sig_hup)(int);
-    void (*sig_term)(int);
-    void (*sig_segv)(int);
-
-    void (*handler)(int);
-};
-static Interrupts interrupts;
-
-static void InterruptHandler(int sig)
+static void (*gCallback)(void) = NULL;
+
+#define NUM_SIGNALS 16
+
+struct sigaction old_actions[NUM_SIGNALS];
+
+static void signal_handler(int sig, siginfo_t *info, void *context)
 {
-    if (interrupts.set && interrupts.handler) {
-        interrupts.handler(sig);
-    }
-    if (sig == SIGINT) {
-        if (!interrupts.sig_int) {
-            exit(sig);
-        }
-        interrupts.sig_int(sig);
-    } else if (sig == SIGHUP) {
-        if (!interrupts.sig_hup) {
-            exit(sig);
-        }
-        interrupts.sig_hup(sig);
-    } else if (sig == SIGTERM) {
-        if (!interrupts.sig_term) {
-            exit(sig);
+    static int recursion_count = 0;
+
+    fprintf(stderr, "signal_handler: sig = %i\n", sig);
+
+    if (recursion_count) {
+        fprintf(stderr, "recursion with sig %i\n", sig);
+    } else {
+        if (gCallback) {
+            ++recursion_count;
+            gCallback();
+            --recursion_count;
         }
-        interrupts.sig_term(sig);
-    } else if (sig == SIGSEGV) {
-        if (interrupts.sig_segv) {
-            interrupts.sig_segv(sig);
+    }
+
+    struct sigaction *old_action;
+    if (sig >= NUM_SIGNALS) {
+        /* This should never happen */
+        fprintf(stderr, "Unexpected signal %i\n", sig);
+        raise(SIGKILL);
+    }
+    old_action = &old_actions[sig];
+
+    if (old_action->sa_flags & SA_SIGINFO) {
+        // Handler is in sa_sigaction
+        old_action->sa_sigaction(sig, info, context);
+    } else {
+        if (old_action->sa_handler == SIG_DFL) {
+            fprintf(stderr, "taking default action for signal %i\n", sig);
+
+#if 1
+            struct sigaction dfl_action;
+            dfl_action.sa_handler = SIG_DFL;
+            sigemptyset (&dfl_action.sa_mask);
+            dfl_action.sa_flags = 0;
+            sigaction(sig, &dfl_action, NULL);
+
+            raise(sig);
+#else
+            raise(SIGKILL);
+#endif
+        } else if (old_action->sa_handler == SIG_IGN) {
+            /* ignore */
+        } else {
+            /* dispatch to handler */
+            old_action->sa_handler(sig);
         }
     }
 }
 
 void
-CatchInterrupts(void (*func)(int))
+SetExceptionCallback(void (*callback)(void))
 {
-    interrupts.handler = func;
+    assert(!gCallback);
+    if (!gCallback) {
+        gCallback = callback;
 
-    if (!interrupts.set) {
-        struct sigaction new_action, old_action;
-        new_action.sa_handler = InterruptHandler;
+        struct sigaction new_action;
+        new_action.sa_sigaction = signal_handler;
         sigemptyset(&new_action.sa_mask);
-        new_action.sa_flags = 0;
-#define SET_IF_NOT_IGNORED(sig, old_handler)            \
-        do {                                            \
-            sigaction(sig, NULL, &old_action);          \
-            if (old_action.sa_handler != SIG_IGN) {     \
-                old_handler = old_action.sa_handler;    \
-                sigaction(sig, &new_action, NULL);      \
-            }                                           \
-        } while (0)
-
-        SET_IF_NOT_IGNORED(SIGINT, interrupts.sig_int);
-        SET_IF_NOT_IGNORED(SIGHUP, interrupts.sig_hup);
-        SET_IF_NOT_IGNORED(SIGTERM, interrupts.sig_term);
-        SET_IF_NOT_IGNORED(SIGSEGV, interrupts.sig_segv);
-
-        interrupts.set = true;
-#undef SET_IF_NOT_IGNORED
+        new_action.sa_flags = SA_SIGINFO | SA_RESTART;
+
+
+        for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
+            // SIGKILL and SIGSTOP can't be handled
+            if (sig != SIGKILL && sig != SIGSTOP) {
+                if (sigaction(sig,  NULL, &old_actions[sig]) >= 0) {
+                    sigaction(sig,  &new_action, NULL);
+                }
+            }
+        }
     }
 }
 
+void
+ResetExceptionCallback(void)
+{
+    gCallback = NULL;
+}
+
 } /* namespace OS */