X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=os_posix.cpp;h=991ad0e7cabef3162162fd19176e2d0b6580c9d6;hb=c592957de1083b4e32ee58c0ea2e5feaa9085b47;hp=c072d5da7c4361a216d36e669fc652d6464e1c86;hpb=3d9a70ca68c1e0eeeec640e90625deb68245a64e;p=apitrace diff --git a/os_posix.cpp b/os_posix.cpp index c072d5d..991ad0e 100644 --- a/os_posix.cpp +++ b/os_posix.cpp @@ -24,6 +24,7 @@ **************************************************************************/ +#include #include #include #include @@ -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 */