]> git.cworth.org Git - apitrace/commitdiff
Signal handling support.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Wed, 24 Aug 2011 18:19:40 +0000 (19:19 +0100)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Wed, 24 Aug 2011 18:19:40 +0000 (19:19 +0100)
Based on Zack Rusin's work, but a bit more generic.

os.hpp
os_posix.cpp
os_win32.cpp

diff --git a/os.hpp b/os.hpp
index 4376c97b50eea2d55a548022907f429476a70196..8e487b502937f02c5e80ae0a292c9c7fd0e7d7d0 100644 (file)
--- a/os.hpp
+++ b/os.hpp
@@ -90,6 +90,9 @@ long long GetTime(void);
 
 void Abort(void);
 
+void SetExceptionCallback(void (*callback)(void));
+void ResetExceptionCallback(void);
+
 } /* namespace OS */
 
 #endif /* _OS_HPP_ */
index cb9b7e59113130b5f696f21a41769aa5c463fc7a..991ad0e7cabef3162162fd19176e2d0b6580c9d6 100644 (file)
@@ -24,6 +24,7 @@
  **************************************************************************/
 
 
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -33,6 +34,7 @@
 #include <pthread.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <signal.h>
 
 #ifdef __APPLE__
 #include <mach-o/dyld.h>
@@ -137,5 +139,92 @@ Abort(void)
 }
 
 
+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)
+{
+    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;
+        }
+    }
+
+    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
+SetExceptionCallback(void (*callback)(void))
+{
+    assert(!gCallback);
+    if (!gCallback) {
+        gCallback = callback;
+
+        struct sigaction new_action;
+        new_action.sa_sigaction = signal_handler;
+        sigemptyset(&new_action.sa_mask);
+        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 */
 
index f220ae5ec46dbbcd7368ca0204a36a669d26c835..587503c41553fa7cd013cf5ad28862fa34f938a7 100644 (file)
@@ -24,6 +24,8 @@
  **************************************************************************/
 
 #include <windows.h>
+#include <assert.h>
+#include <signal.h>
 #include <string.h>
 #include <stdio.h>
 
@@ -133,4 +135,41 @@ Abort(void)
 #endif
 }
 
+
+static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
+static void (*gCallback)(void) = NULL;
+
+static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
+{
+    if (gCallback) {
+        gCallback();
+    }
+
+       if (prevExceptionFilter) {
+               return prevExceptionFilter(pExceptionInfo);
+    } else {
+               return EXCEPTION_CONTINUE_SEARCH;
+    }
+}
+
+void
+SetExceptionCallback(void (*callback)(void))
+{
+    assert(!gCallback);
+
+    if (!gCallback) {
+        gCallback = callback;
+
+        assert(!prevExceptionFilter);
+        prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
+    }
+}
+
+void
+ResetExceptionCallback(void)
+{
+    gCallback = NULL;
+}
+
+
 } /* namespace OS */