From: William Harold Newman Date: Sat, 26 May 2001 20:33:48 +0000 (+0000) Subject: 0.6.12.15: X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=358cad8bdef5c670e1bbe94c430bd27544995433;p=sbcl.git 0.6.12.15: turned interrupt_install_low_level_handler() into undoably_install_low_level_interrupt_handler(), which uses atexit() to arrange for the handler to be removed at exit, for tidiness in general and specifically because without the the interaction between the GC and the exit()-time segfaults caused by memory corruption is making it tricky to debug the OpenBSD port --- diff --git a/src/runtime/alpha-arch.c b/src/runtime/alpha-arch.c index 93c7cae..4053163 100644 --- a/src/runtime/alpha-arch.c +++ b/src/runtime/alpha-arch.c @@ -338,9 +338,9 @@ static void sigfpe_handler(int signal, int code, os_context_t *context) void arch_install_interrupt_handlers() { - interrupt_install_low_level_handler(SIGILL,sigill_handler); - interrupt_install_low_level_handler(SIGTRAP,sigtrap_handler); - interrupt_install_low_level_handler(SIGFPE,sigfpe_handler); + undoably_install_low_level_interrupt_handler(SIGILL, sigill_handler); + undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); + undoably_install_low_level_interrupt_handler(SIGFPE, sigfpe_handler); } extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs); diff --git a/src/runtime/bsd-os.c b/src/runtime/bsd-os.c index 5fecc6e..4660240 100644 --- a/src/runtime/bsd-os.c +++ b/src/runtime/bsd-os.c @@ -235,11 +235,11 @@ os_install_interrupt_handlers(void) { SHOW("os_install_interrupt_handlers()/bsd-os/defined(GENCGC)"); #if defined __FreeBSD__ - SHOW("__FreeBSD__ case"); - interrupt_install_low_level_handler(SIGBUS, memory_fault_handler); + undoably_install_low_level_interrupt_handler(SIGBUS, + memory_fault_handler); #elif defined __OpenBSD__ - FSHOW((stderr, "/__OpenBSD__ case, SIGSEGV=%d\n", SIGSEGV)); - interrupt_install_low_level_handler(SIGSEGV, memory_fault_handler); + undoably_install_low_level_interrupt_handler(SIGSEGV, + memory_fault_handler); #else #error unsupported BSD variant #endif diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index ecc3b84..4dc22af 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -565,20 +565,74 @@ interrupt_maybe_gc(int signal, siginfo_t *info, void *void_context) * noise to install handlers */ +/* + * what low-level signal handlers looked like before + * undoably_install_low_level_interrupt_handler() got involved + */ +struct low_level_signal_handler_state { + int was_modified; + void (*handler)(int, siginfo_t*, void*); +} old_low_level_signal_handler_states[NSIG]; + +void +uninstall_low_level_interrupt_handlers_atexit(void) +{ + int signal; + for (signal = 0; signal < NSIG; ++signal) { + struct low_level_signal_handler_state + *old_low_level_signal_handler_state = + old_low_level_signal_handler_states + signal; + if (old_low_level_signal_handler_state->was_modified) { + struct sigaction sa; + sa.sa_sigaction = old_low_level_signal_handler_state->handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sigaction(signal, &sa, NULL); + } + } +} + /* Install a special low-level handler for signal; or if handler is - * SIG_DFL, remove any special handling for signal. */ + * SIG_DFL, remove any special handling for signal. + * + * The "undoably_" part is because we also arrange with atexit() for + * the handler to be restored to its old value. This is for tidiness, + * though it shouldn't really matter in normal operation of the + * program, except perhaps that it removes a window when e.g. SIGINT + * would be handled bizarrely. The original motivation was that some + * memory corruption problems in OpenBSD ca sbcl-0.6.12.12 became + * unnecessarily hard to debug when they ended up back in gencgc.c + * code (courtesy of the gencgc SIGSEGV handler) after exit() was + * called. */ void -interrupt_install_low_level_handler (int signal, - void handler(int, siginfo_t*, void*)) +undoably_install_low_level_interrupt_handler (int signal, + void handler(int, + siginfo_t*, + void*)) { struct sigaction sa; + struct low_level_signal_handler_state *old_low_level_signal_handler_state = + old_low_level_signal_handler_states + signal; + + if (0 > signal || signal >= NSIG) { + lose("bad signal number %d", signal); + } sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); sigaddset_blockable(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_RESTART; - sigaction(signal, &sa, NULL); + /* In the case of interrupt handlers which are modified + * more than once, we only save the original unmodified + * copy. */ + if (!old_low_level_signal_handler_state->was_modified) { + old_low_level_signal_handler_state->was_modified = 1; + sigaction(signal, &sa, &old_low_level_signal_handler_state->handler); + } else { + sigaction(signal, &sa, NULL); + } + interrupt_low_level_handlers[signal] = (ARE_SAME_HANDLER(handler,SIG_DFL) ? 0 : handler); } @@ -635,6 +689,11 @@ interrupt_init(void) int i; SHOW("entering interrupt_init()"); + + /* Set up for recovery from any installed low-level handlers. */ + atexit(&uninstall_low_level_interrupt_handlers_atexit); + + /* Set up high level handler information. */ for (i = 0; i < NSIG; i++) { interrupt_handlers[i].c = /* (The cast here blasts away the distinction between @@ -644,5 +703,6 @@ interrupt_init(void) * 3-argument form is expected.) */ (void (*)(int, siginfo_t*, void*))SIG_DFL; } + SHOW("returning from interrupt_init()"); } diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index c4145f2..73ab2d2 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -36,10 +36,11 @@ extern void interrupt_handle_pending(os_context_t*); extern void interrupt_internal_error(int, siginfo_t*, os_context_t*, boolean continuable); extern boolean interrupt_maybe_gc(int, siginfo_t*, void*); -extern void interrupt_install_low_level_handler (int signal, - void handler(int, - siginfo_t*, - void*)); +extern void undoably_install_low_level_interrupt_handler (int signal, + void + handler(int, + siginfo_t*, + void*)); extern unsigned long install_handler(int signal, void handler(int, siginfo_t*, void*)); diff --git a/src/runtime/linux-os.c b/src/runtime/linux-os.c index 3e68e12..e09565f 100644 --- a/src/runtime/linux-os.c +++ b/src/runtime/linux-os.c @@ -289,6 +289,6 @@ sigsegv_handler(int signal, siginfo_t *info, void* void_context) void os_install_interrupt_handlers(void) { - interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler); + undoably_install_low_level_interrupt_handler(SIGSEGV, sigsegv_handler); } diff --git a/src/runtime/x86-arch.c b/src/runtime/x86-arch.c index 16b669a..acf9280 100644 --- a/src/runtime/x86-arch.c +++ b/src/runtime/x86-arch.c @@ -266,8 +266,8 @@ void arch_install_interrupt_handlers() { SHOW("entering arch_install_interrupt_handlers()"); - interrupt_install_low_level_handler(SIGILL , sigtrap_handler); - interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler); + undoably_install_low_level_interrupt_handler(SIGILL , sigtrap_handler); + undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); SHOW("returning from arch_install_interrupt_handlers()"); } diff --git a/version.lisp-expr b/version.lisp-expr index ff4a8b8..9c62f13 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -15,4 +15,4 @@ ;;; versions, and a string like "0.6.5.12" is used for versions which ;;; aren't released but correspond only to CVS tags or snapshots. -"0.6.12.14" +"0.6.12.15"