From ff599707342966a144ff47eea3c84256aed015bc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Wed, 24 Aug 2011 19:19:40 +0100 Subject: [PATCH] Signal handling support. Based on Zack Rusin's work, but a bit more generic. --- os.hpp | 3 ++ os_posix.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ os_win32.cpp | 39 +++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/os.hpp b/os.hpp index 4376c97..8e487b5 100644 --- 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_ */ diff --git a/os_posix.cpp b/os_posix.cpp index cb9b7e5..991ad0e 100644 --- a/os_posix.cpp +++ b/os_posix.cpp @@ -24,6 +24,7 @@ **************************************************************************/ +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #ifdef __APPLE__ #include @@ -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 */ diff --git a/os_win32.cpp b/os_win32.cpp index f220ae5..587503c 100644 --- a/os_win32.cpp +++ b/os_win32.cpp @@ -24,6 +24,8 @@ **************************************************************************/ #include +#include +#include #include #include @@ -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 */ -- 2.45.2