X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Finterrupt.c;h=bc6ed906948c14a0b65bd3fa225f3bbd2fd9861b;hb=dfa55a883f94470267b626dae77ce7e7dfac3df6;hp=a3fd5a0ef297cf072a06c292a5ee6bdbc16bd6ed;hpb=cb7837b769ce190baec60a2159c33099816ea6e3;p=sbcl.git diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index a3fd5a0..bc6ed90 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -73,17 +73,25 @@ os_context_t *lisp_interrupt_contexts[MAX_INTERRUPTS]; * In that case, the Lisp-level handler is stored in interrupt_handlers[..] * and interrupt_low_level_handlers[..] is cleared. * - * However, some signals need special handling, e.g. the SIGSEGV (for - * Linux) or SIGBUS (for FreeBSD) used by the garbage collector to - * detect violations of write protection, because some cases of such - * signals (e.g. GC-related violations of write protection) are - * handled at C level and never passed on to Lisp. For such signals, - * we still store any Lisp-level handler in interrupt_handlers[..], - * but for the outermost handle we use the value from - * interrupt_low_level_handlers[..], instead of the ordinary - * interrupt_handle_now(..) or interrupt_handle_later(..). + * However, some signals need special handling, e.g. * - * -- WHN 20000728 */ + * o the SIGSEGV (for Linux) or SIGBUS (for FreeBSD) used by the + * garbage collector to detect violations of write protection, + * because some cases of such signals (e.g. GC-related violations of + * write protection) are handled at C level and never passed on to + * Lisp. For such signals, we still store any Lisp-level handler + * in interrupt_handlers[..], but for the outermost handle we use + * the value from interrupt_low_level_handlers[..], instead of the + * ordinary interrupt_handle_now(..) or interrupt_handle_later(..). + * + * o the SIGTRAP (Linux/Alpha) which Lisp code uses to handle breakpoints, + * pseudo-atomic sections, and some classes of error (e.g. "function + * not defined"). This never goes anywhere near the Lisp handlers at all. + * See runtime/alpha-arch.c and code/signal.lisp + * + * - WHN 20000728, dan 20010128 */ + + void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, void*) = {0}; union interrupt_handler interrupt_handlers[NSIG]; @@ -234,6 +242,7 @@ interrupt_internal_error(int signal, siginfo_t *info, os_context_t *context, if (internal_errors_enabled) { SHOW("in interrupt_internal_error"); +#define QSHOW 1 #if QSHOW /* Display some rudimentary debugging information about the * error, so that even if the Lisp error handler gets badly @@ -254,6 +263,13 @@ interrupt_internal_error(int signal, siginfo_t *info, os_context_t *context, } } +/* This function handles pending interrupts. Note that in C/kernel + * terms we dealt with the signal already; we just haven't decided + * whether to call a Lisp handler or do a GC or something like that. + * If it helps, you can think of pending_{signal,mask,info} as a + * one-element queue of signals that we have acknowledged but not + * processed */ + void interrupt_handle_pending(os_context_t *context) { @@ -378,9 +394,8 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context) * (FIXME: Why? This is the way it was done in CMU CL, and it * even had the comment noting that this is the way it was * done, but no motivation..) */ - lispobj context_sap = alloc_sap(context); - lispobj info_sap = alloc_sap(info); - + lispobj info_sap,context_sap = alloc_sap(context); + info_sap = alloc_sap(info); /* Allow signals again. */ sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0); @@ -428,6 +443,9 @@ maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context) * SET_FPU_CONTROL_WORD(context->__fpregs_mem.cw); * #endif */ + /* see comments at top of code/signal.lisp for what's going on here + * with INTERRUPTS_ENABLED/INTERRUPT_HANDLE_NOW + */ if (SymbolValue(INTERRUPTS_ENABLED) == NIL) { /* FIXME: This code is exactly the same as the code in the @@ -439,7 +457,6 @@ maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context) os_context_sigmask_addr(context), sizeof(sigset_t)); sigaddset_blockable(os_context_sigmask_addr(context)); - SetSymbolValue(INTERRUPT_PENDING, T); } else if ( @@ -483,15 +500,21 @@ gc_trigger_hit(int signal, siginfo_t *info, os_context_t *context) context); return (badaddr >= current_auto_gc_trigger && - badaddr < DYNAMIC_SPACE_START + DYNAMIC_SPACE_SIZE); + badaddr < current_dynamic_space + DYNAMIC_SPACE_SIZE); } } #endif #ifndef __i386__ +/* This function gets called from the SIGSEGV (Linux) or SIGBUS (BSD) + * handler. Here we check whether the signal was due to treading on + * the mprotect()ed zone - and if so, arrange for a GC to happen. + */ boolean -interrupt_maybe_gc(int signal, siginfo_t *info, os_context_t *context) +interrupt_maybe_gc(int signal, siginfo_t *info, void *void_context) { + os_context_t *context=(os_context_t *) void_context; + if (!foreign_function_call_active #ifndef INTERNAL_GC_TRIGGER && gc_trigger_hit(signal, info, context) @@ -502,6 +525,10 @@ interrupt_maybe_gc(int signal, siginfo_t *info, os_context_t *context) #endif if (arch_pseudo_atomic_atomic(context)) { + /* don't GC during an atomic operation. Instead, copy the + * signal mask somewhere safe. interrupt_handle_pending + * will detect pending_signal==0 and know to do a GC with the + * signal context instead of calling a Lisp-level handler */ maybe_gc_pending = 1; if (pending_signal == 0) { /* FIXME: This copy-pending_mask-then-sigaddset_blockable