From: Gabor Melis Date: Sun, 22 Mar 2009 21:44:07 +0000 (+0000) Subject: 1.0.26.15: interrupt.c refactoring X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=cf507f95509a855a752b6f1771aa06877b8a3b30;p=sbcl.git 1.0.26.15: interrupt.c refactoring - check that all or none of the deferrable signals are blocked - make passing NULL for sigset in the right context mean the current sigmask: there is only a single block_signals() function that can performs sigset arithmetic or change the current mask. - print pc and sp on memory faults to ease debugging --- diff --git a/src/code/target-signal.lisp b/src/code/target-signal.lisp index 87cf646..b660735 100644 --- a/src/code/target-signal.lisp +++ b/src/code/target-signal.lisp @@ -99,8 +99,22 @@ ;;; doing things the SBCL way and moving this kind of C-level work ;;; down to C wrapper functions.) -(sb!alien:define-alien-routine "unblock_deferrable_signals" sb!alien:void) -(sb!alien:define-alien-routine "unblock_gc_signals" sb!alien:void) +(declaim (inline %unblock-deferrable-signals %unblock-gc-signals)) +(sb!alien:define-alien-routine ("unblock_deferrable_signals" + %unblock-deferrable-signals) + sb!alien:void + (where sb!alien:unsigned-long) + (old sb!alien:unsigned-long)) +(sb!alien:define-alien-routine ("unblock_gc_signals" %unblock-gc-signals) + sb!alien:void + (where sb!alien:unsigned-long) + (old sb!alien:unsigned-long)) + +(defun unblock-deferrable-signals () + (%unblock-deferrable-signals 0 0)) + +(defun unblock-gc-signals () + (%unblock-gc-signals 0 0)) ;;;; C routines that actually do all the work of establishing signal handlers diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index 2130213..2021cfb 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -120,8 +120,14 @@ in future versions." (define-alien-routine ("create_thread" %create-thread) unsigned-long (lisp-fun-address unsigned-long)) - (define-alien-routine "block_deferrable_signals" - void) + (declaim (inline %block-deferrable-signals)) + (define-alien-routine ("block_deferrable_signals" %block-deferrable-signals) + void + (where sb!alien:unsigned-long) + (old sb!alien:unsigned-long)) + + (defun block-deferrable-signals () + (%block-deferrable-signals 0 0)) #!+sb-lutex (progn diff --git a/src/runtime/alloc.c b/src/runtime/alloc.c index 500bfb0..b84df30 100644 --- a/src/runtime/alloc.c +++ b/src/runtime/alloc.c @@ -44,7 +44,7 @@ pa_alloc(int bytes, int page_type_flag) * otherwise two threads racing here may deadlock: the other will * wait on the GC lock, and the other cannot stop the first * one... */ - check_gc_signals_unblocked_or_lose(); + check_gc_signals_unblocked_or_lose(0); /* FIXME: OOAO violation: see arch_pseudo_* */ set_pseudo_atomic_atomic(th); @@ -94,7 +94,7 @@ pa_alloc(int bytes, int page_type_flag) /* This is not pseudo atomic at all, but is called only from * interrupt safe places like interrupt handlers. MG - * 2005-08-09 */ - check_deferrables_blocked_or_lose(); + check_deferrables_blocked_or_lose(0); result = dynamic_space_free_pointer; diff --git a/src/runtime/backtrace.c b/src/runtime/backtrace.c index a36d373..2d7dfca 100644 --- a/src/runtime/backtrace.c +++ b/src/runtime/backtrace.c @@ -534,7 +534,7 @@ describe_thread_state(void) sigset_t mask; struct thread *thread = arch_os_get_current_thread(); #ifndef LISP_FEATURE_WIN32 - thread_sigmask(SIG_SETMASK, NULL, &mask); + get_current_sigmask(&mask); printf("Signal mask:\n"); printf(" SIGALRM = %d\n", sigismember(&mask, SIGALRM)); printf(" SIGINT = %d\n", sigismember(&mask, SIGINT)); diff --git a/src/runtime/breakpoint.c b/src/runtime/breakpoint.c index 5dfa9a4..45639c4 100644 --- a/src/runtime/breakpoint.c +++ b/src/runtime/breakpoint.c @@ -130,7 +130,7 @@ void handle_breakpoint(os_context_t *context) fake_foreign_function_call(context); - unblock_gc_signals(); + unblock_gc_signals(0, 0); context_sap = alloc_sap(context); code = find_code(context); @@ -155,7 +155,7 @@ void *handle_fun_end_breakpoint(os_context_t *context) fake_foreign_function_call(context); - unblock_gc_signals(); + unblock_gc_signals(0, 0); context_sap = alloc_sap(context); code = find_code(context); codeptr = (struct code *)native_pointer(code); diff --git a/src/runtime/cheneygc.c b/src/runtime/cheneygc.c index 78c0ea4..62bd6de 100644 --- a/src/runtime/cheneygc.c +++ b/src/runtime/cheneygc.c @@ -132,9 +132,7 @@ collect_garbage(generation_index_t ignore) /* it's possible that signals are blocked already if this was called * from a signal handler (e.g. with the sigsegv gc_trigger stuff) */ - sigemptyset(&tmp); - sigaddset_blockable(&tmp); - thread_sigmask(SIG_BLOCK, &tmp, &old); + block_blockable_signals(0, &old); current_static_space_free_pointer = (lispobj *) ((unsigned long) diff --git a/src/runtime/funcall.c b/src/runtime/funcall.c index 186435c..91f5513 100644 --- a/src/runtime/funcall.c +++ b/src/runtime/funcall.c @@ -31,7 +31,7 @@ safe_call_into_lisp(lispobj fun, lispobj *args, int nargs) * otherwise two threads racing here may deadlock: the other will * wait on the GC lock, and the other cannot stop the first * one... */ - check_gc_signals_unblocked_or_lose(); + check_gc_signals_unblocked_or_lose(0); return call_into_lisp(fun, args, nargs); } diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c index 057be12..c358039 100644 --- a/src/runtime/gc-common.c +++ b/src/runtime/gc-common.c @@ -2433,9 +2433,8 @@ maybe_gc(os_context_t *context) * outer context. */ #ifndef LISP_FEATURE_WIN32 - check_gc_signals_unblocked_in_sigset_or_lose - (os_context_sigmask_addr(context)); - unblock_gc_signals(); + check_gc_signals_unblocked_or_lose(os_context_sigmask_addr(context)); + unblock_gc_signals(0, 0); #endif FSHOW((stderr, "/maybe_gc: calling SUB_GC\n")); /* FIXME: Nothing must go wrong during GC else we end up running @@ -2456,9 +2455,9 @@ maybe_gc(os_context_t *context) (SymbolValue(ALLOW_WITH_INTERRUPTS,thread) != NIL))) { #ifndef LISP_FEATURE_WIN32 sigset_t *context_sigmask = os_context_sigmask_addr(context); - if (!deferrables_blocked_in_sigset_p(context_sigmask)) { + if (!deferrables_blocked_p(context_sigmask)) { thread_sigmask(SIG_SETMASK, context_sigmask, 0); - check_gc_signals_unblocked_or_lose(); + check_gc_signals_unblocked_or_lose(0); #endif FSHOW((stderr, "/maybe_gc: calling POST_GC\n")); funcall0(StaticSymbolFunction(POST_GC)); diff --git a/src/runtime/interr.c b/src/runtime/interr.c index f7da2d3..3b0a882 100644 --- a/src/runtime/interr.c +++ b/src/runtime/interr.c @@ -79,7 +79,7 @@ lose(char *fmt, ...) va_list ap; /* Block signals to prevent other threads, timers and such from * interfering. If only all threads could be stopped somehow. */ - block_blockable_signals(); + block_blockable_signals(0, 0); fprintf(stderr, "fatal error encountered"); va_start(ap, fmt); print_message(fmt, ap); @@ -97,7 +97,7 @@ corruption_warning_and_maybe_lose(char *fmt, ...) va_list ap; #ifndef LISP_FEATURE_WIN32 sigset_t oldset; - thread_sigmask(SIG_BLOCK, &blockable_sigset, &oldset); + block_blockable_signals(0, &oldset); #endif fprintf(stderr, "CORRUPTION WARNING"); va_start(ap, fmt); diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index 305f75f..8c87054 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -116,15 +116,95 @@ static void store_signal_data_for_later (struct interrupt_data *data, void *handler, int signal, siginfo_t *info, os_context_t *context); + -static void -fill_current_sigmask(sigset_t *sigset) +/* Generic signal related utilities. */ + +void +get_current_sigmask(sigset_t *sigset) { /* Get the current sigmask, by blocking the empty set. */ - sigset_t empty; - sigemptyset(&empty); - thread_sigmask(SIG_BLOCK, &empty, sigset); + thread_sigmask(SIG_BLOCK, 0, sigset); +} + +void +block_signals(sigset_t *what, sigset_t *where, sigset_t *old) +{ + if (where) { + int i; + if (old) + sigcopyset(old, where); + for(i = 1; i < NSIG; i++) { + if (sigismember(what, i)) + sigaddset(where, i); + } + } else { + thread_sigmask(SIG_BLOCK, what, old); + } +} + +void +unblock_signals(sigset_t *what, sigset_t *where, sigset_t *old) +{ + if (where) { + int i; + if (old) + sigcopyset(old, where); + for(i = 1; i < NSIG; i++) { + if (sigismember(what, i)) + sigdelset(where, i); + } + } else { + thread_sigmask(SIG_UNBLOCK, what, old); + } +} + +static void +print_sigset(sigset_t *sigset) +{ + int i; + for(i = 1; i < NSIG; i++) { + if (sigismember(sigset, i)) + fprintf(stderr, "Signal %d masked\n", i); + } +} + +/* Return 1 is all signals is sigset2 are masked in sigset, return 0 + * if all re unmasked else die. Passing NULL for sigset is a shorthand + * for the current sigmask. */ +boolean +all_signals_blocked_p(sigset_t *sigset, sigset_t *sigset2, + const char *name) +{ +#if !defined(LISP_FEATURE_WIN32) + int i; + boolean has_blocked = 0, has_unblocked = 0; + sigset_t current; + if (sigset == 0) { + get_current_sigmask(¤t); + sigset = ¤t; + } + for(i = 1; i < NSIG; i++) { + if (sigismember(sigset2, i)) { + if (sigismember(sigset, i)) + has_blocked = 1; + else + has_unblocked = 1; + } + } + if (has_blocked && has_unblocked) { + print_sigset(sigset); + lose("some %s signals blocked, some unblocked\n", name); + } + if (has_blocked) + return 1; + else + return 0; +#endif } + + +/* Deferrables, blockables, gc signals. */ void sigaddset_deferrable(sigset_t *s) @@ -149,27 +229,6 @@ sigaddset_deferrable(sigset_t *s) } void -sigdelset_deferrable(sigset_t *s) -{ - sigdelset(s, SIGHUP); - sigdelset(s, SIGINT); - sigdelset(s, SIGQUIT); - sigdelset(s, SIGPIPE); - sigdelset(s, SIGALRM); - sigdelset(s, SIGURG); - sigdelset(s, SIGTSTP); - sigdelset(s, SIGCHLD); - sigdelset(s, SIGIO); -#ifndef LISP_FEATURE_HPUX - sigdelset(s, SIGXCPU); - sigdelset(s, SIGXFSZ); -#endif - sigdelset(s, SIGVTALRM); - sigdelset(s, SIGPROF); - sigdelset(s, SIGWINCH); -} - -void sigaddset_blockable(sigset_t *sigset) { sigaddset_deferrable(sigset); @@ -184,113 +243,155 @@ sigaddset_gc(sigset_t *sigset) #endif } -void -sigdelset_gc(sigset_t *sigset) -{ -#ifdef LISP_FEATURE_SB_THREAD - sigdelset(sigset,SIG_STOP_FOR_GC); -#endif -} - /* initialized in interrupt_init */ sigset_t deferrable_sigset; sigset_t blockable_sigset; sigset_t gc_sigset; + #endif boolean -deferrables_blocked_in_sigset_p(sigset_t *sigset) +deferrables_blocked_p(sigset_t *sigset) +{ + return all_signals_blocked_p(sigset, &deferrable_sigset, "deferrable"); +} + +void +check_deferrables_unblocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - int i; - for(i = 1; i < NSIG; i++) { - if (sigismember(&deferrable_sigset, i) && sigismember(sigset, i)) - return 1; - } + if (deferrables_blocked_p(sigset)) + lose("deferrables blocked\n"); #endif - return 0; } void -check_deferrables_unblocked_in_sigset_or_lose(sigset_t *sigset) +check_deferrables_blocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - int i; - for(i = 1; i < NSIG; i++) { - if (sigismember(&deferrable_sigset, i) && sigismember(sigset, i)) - lose("deferrable signal %d blocked\n",i); - } + if (!deferrables_blocked_p(sigset)) + lose("deferrables unblocked\n"); #endif } +boolean +blockables_blocked_p(sigset_t *sigset) +{ + return all_signals_blocked_p(sigset, &blockable_sigset, "blockable"); +} + void -check_deferrables_blocked_in_sigset_or_lose(sigset_t *sigset) +check_blockables_unblocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - int i; - for(i = 1; i < NSIG; i++) { - if (sigismember(&deferrable_sigset, i) && !sigismember(sigset, i)) - lose("deferrable signal %d not blocked\n",i); - } + if (blockables_blocked_p(sigset)) + lose("blockables blocked\n"); #endif } void -check_deferrables_unblocked_or_lose(void) +check_blockables_blocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - sigset_t current; - fill_current_sigmask(¤t); - check_deferrables_unblocked_in_sigset_or_lose(¤t); + if (!blockables_blocked_p(sigset)) + lose("blockables unblocked\n"); #endif } +boolean +gc_signals_blocked_p(sigset_t *sigset) +{ + return all_signals_blocked_p(sigset, &gc_sigset, "gc"); +} + void -check_deferrables_blocked_or_lose(void) +check_gc_signals_unblocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - sigset_t current; - fill_current_sigmask(¤t); - check_deferrables_blocked_in_sigset_or_lose(¤t); + if (gc_signals_blocked_p(sigset)) + lose("gc signals blocked\n"); #endif } void -check_blockables_blocked_or_lose(void) +check_gc_signals_blocked_or_lose(sigset_t *sigset) { #if !defined(LISP_FEATURE_WIN32) - sigset_t current; - int i; - fill_current_sigmask(¤t); - for(i = 1; i < NSIG; i++) { - if (sigismember(&blockable_sigset, i) && !sigismember(¤t, i)) - lose("blockable signal %d not blocked\n",i); - } + if (!gc_signals_blocked_p(sigset)) + lose("gc signals unblocked\n"); #endif } void -check_gc_signals_unblocked_in_sigset_or_lose(sigset_t *sigset) +block_deferrable_signals(sigset_t *where, sigset_t *old) { -#if !defined(LISP_FEATURE_WIN32) - int i; - for(i = 1; i < NSIG; i++) { - if (sigismember(&gc_sigset, i) && sigismember(sigset, i)) - lose("gc signal %d blocked\n",i); - } +#ifndef LISP_FEATURE_WIN32 + block_signals(&deferrable_sigset, where, old); #endif } void -check_gc_signals_unblocked_or_lose(void) +block_blockable_signals(sigset_t *where, sigset_t *old) { -#if !defined(LISP_FEATURE_WIN32) - sigset_t current; - fill_current_sigmask(¤t); - check_gc_signals_unblocked_in_sigset_or_lose(¤t); +#ifndef LISP_FEATURE_WIN32 + block_signals(&blockable_sigset, where, old); #endif } +void +block_gc_signals(sigset_t *where, sigset_t *old) +{ +#ifndef LISP_FEATURE_WIN32 + block_signals(&gc_sigset, where, old); +#endif +} + +void +unblock_deferrable_signals(sigset_t *where, sigset_t *old) +{ +#ifndef LISP_FEATURE_WIN32 + if (interrupt_handler_pending_p()) + lose("unblock_deferrable_signals: losing proposition\n"); + check_gc_signals_unblocked_or_lose(where); + unblock_signals(&deferrable_sigset, where, old); +#endif +} + +void +unblock_blockable_signals(sigset_t *where, sigset_t *old) +{ +#ifndef LISP_FEATURE_WIN32 + unblock_signals(&blockable_sigset, where, old); +#endif +} + +void +unblock_gc_signals(sigset_t *where, sigset_t *old) +{ +#ifndef LISP_FEATURE_WIN32 + unblock_signals(&gc_sigset, where, old); +#endif +} + +void +unblock_signals_in_context_and_maybe_warn(os_context_t *context) +{ +#ifndef LISP_FEATURE_WIN32 + sigset_t *sigset = os_context_sigmask_addr(context); + if (all_signals_blocked_p(sigset, &gc_sigset, "gc")) { + corruption_warning_and_maybe_lose( +"Enabling blocked gc signals to allow returning to Lisp without risking\n\ +gc deadlocks. Since GC signals are only blocked in signal handlers when \n\ +they are not safe to interrupt at all, this is a pretty severe occurrence.\n"); + unblock_gc_signals(sigset, 0); + } + if (!interrupt_handler_pending_p()) { + unblock_deferrable_signals(sigset, 0); + } +#endif +} + + inline static void check_interrupts_enabled_or_lose(os_context_t *context) { @@ -315,7 +416,7 @@ maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset) sigset_t oldset; /* Obviously, this function is called when signals may not be * blocked. Let's make sure we are not interrupted. */ - thread_sigmask(SIG_BLOCK, &blockable_sigset, &oldset); + block_blockable_signals(0, &oldset); #ifndef LISP_FEATURE_SB_THREAD /* With threads a SIG_STOP_FOR_GC and a normal GC may also want to * block. */ @@ -337,7 +438,7 @@ maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset) * unblock gc signals. In the end, this is equivalent to * blocking the deferrables. */ sigcopyset(&data->pending_mask, &oldset); - unblock_gc_signals(); + thread_sigmask(SIG_UNBLOCK, &gc_sigset, 0); return; } } @@ -405,15 +506,15 @@ check_interrupt_context_or_lose(os_context_t *context) if ((data->gc_blocked_deferrables) && interrupt_pending) lose("gc_blocked_deferrables and interrupt pending\n."); if (data->gc_blocked_deferrables) - check_deferrables_blocked_in_sigset_or_lose(sigset); + check_deferrables_blocked_or_lose(sigset); if (interrupt_pending || interrupt_deferred_p || data->gc_blocked_deferrables) - check_deferrables_blocked_in_sigset_or_lose(sigset); + check_deferrables_blocked_or_lose(sigset); else { - check_deferrables_unblocked_in_sigset_or_lose(sigset); + check_deferrables_unblocked_or_lose(sigset); /* If deferrables are unblocked then we are open to signals * that run lisp code. */ - check_gc_signals_unblocked_in_sigset_or_lose(sigset); + check_gc_signals_unblocked_or_lose(sigset); } #endif } @@ -431,76 +532,6 @@ void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, os_context_t*); #endif union interrupt_handler interrupt_handlers[NSIG]; -void -block_blockable_signals(void) -{ -#ifndef LISP_FEATURE_WIN32 - thread_sigmask(SIG_BLOCK, &blockable_sigset, 0); -#endif -} - -void -block_deferrable_signals(void) -{ -#ifndef LISP_FEATURE_WIN32 - thread_sigmask(SIG_BLOCK, &deferrable_sigset, 0); -#endif -} - -void -unblock_deferrable_signals_in_sigset(sigset_t *sigset) -{ -#ifndef LISP_FEATURE_WIN32 - if (interrupt_handler_pending_p()) - lose("unblock_deferrable_signals_in_sigset: losing proposition\n"); - check_gc_signals_unblocked_in_sigset_or_lose(sigset); - sigdelset_deferrable(sigset); -#endif -} - -void -unblock_deferrable_signals(void) -{ -#ifndef LISP_FEATURE_WIN32 - if (interrupt_handler_pending_p()) - lose("unblock_deferrable_signals: losing proposition\n"); - check_gc_signals_unblocked_or_lose(); - thread_sigmask(SIG_UNBLOCK, &deferrable_sigset, 0); -#endif -} - -void -unblock_gc_signals(void) -{ -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_WIN32) - thread_sigmask(SIG_UNBLOCK,&gc_sigset,0); -#endif -} - -void -unblock_signals_in_context_and_maybe_warn(os_context_t *context) -{ -#ifndef LISP_FEATURE_WIN32 - int i, oops=0; - sigset_t *sigset=os_context_sigmask_addr(context); - for(i = 1; i < NSIG; i++) { - if (sigismember(&gc_sigset, i) && sigismember(sigset, i)) { - if (!oops) { - fprintf(stderr, -"Enabling blocked gc signals to allow returning to Lisp without risking\n\ -gc deadlocks. Since GC signals are only blocked in signal handlers when \n\ -they are not safe to interrupt at all, this is a pretty severe occurrence.\n"); - } - oops=1; - } - } - sigdelset_gc(sigset); - if (!interrupt_handler_pending_p()) { - unblock_deferrable_signals_in_sigset(sigset); - } -#endif -} - /* * utility routines used by various signal handlers @@ -568,7 +599,7 @@ fake_foreign_function_call(os_context_t *context) struct thread *thread=arch_os_get_current_thread(); /* context_index incrementing must not be interrupted */ - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); /* Get current Lisp state from context. */ #ifdef reg_ALLOC @@ -624,7 +655,7 @@ undo_fake_foreign_function_call(os_context_t *context) { struct thread *thread=arch_os_get_current_thread(); /* Block all blockable signals. */ - block_blockable_signals(); + block_blockable_signals(0, 0); #ifdef FOREIGN_FUNCTION_CALL_FLAG foreign_function_call_active = 0; @@ -665,7 +696,7 @@ interrupt_internal_error(os_context_t *context, boolean continuable) /* Allocate the SAP object while the interrupts are still * disabled. */ - unblock_gc_signals(); + unblock_gc_signals(0, 0); context_sap = alloc_sap(context); #ifndef LISP_FEATURE_WIN32 @@ -730,7 +761,7 @@ interrupt_handle_pending(os_context_t *context) FSHOW_SIGNAL((stderr, "/entering interrupt_handle_pending\n")); - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); /* If GC/SIG_STOP_FOR_GC struck during PA and there was no pending * handler, then the pending mask was saved and @@ -810,7 +841,7 @@ interrupt_handle_pending(os_context_t *context) lose("Trapping to run pending handler while GC in progress."); } - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); /* No GC shall be lost. If SUB_GC triggers another GC then * that should be handled on the spot. */ @@ -861,7 +892,7 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) #endif union interrupt_handler handler; - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); #ifndef LISP_FEATURE_WIN32 if (sigismember(&deferrable_sigset,signal)) @@ -912,7 +943,7 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) lispobj info_sap, context_sap; /* Leave deferrable signals blocked, the handler itself will * allow signals again when it sees fit. */ - unblock_gc_signals(); + unblock_gc_signals(0, 0); context_sap = alloc_sap(context); info_sap = alloc_sap(info); @@ -973,7 +1004,7 @@ maybe_defer_handler(void *handler, struct interrupt_data *data, { struct thread *thread=arch_os_get_current_thread(); - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); if (SymbolValue(INTERRUPT_PENDING,thread) != NIL) lose("interrupt already pending\n"); @@ -1066,7 +1097,7 @@ low_level_interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) { /* No FP control fixage needed, caller has done that. */ - check_blockables_blocked_or_lose(); + check_blockables_blocked_or_lose(0); check_interrupts_enabled_or_lose(context); (*interrupt_low_level_handlers[signal])(signal, info, context); /* No Darwin context fixage needed, caller does that. */ @@ -1093,7 +1124,6 @@ void sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) { struct thread *thread=arch_os_get_current_thread(); - sigset_t ss; /* Test for GC_INHIBIT _first_, else we'd trap on every single * pseudo atomic until gc is finally allowed. */ @@ -1117,10 +1147,6 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) /* need the context stored so it can have registers scavenged */ fake_foreign_function_call(context); - /* Block everything. */ - sigfillset(&ss); - thread_sigmask(SIG_BLOCK,&ss,0); - /* Not pending anymore. */ SetSymbolValue(GC_PENDING,NIL,thread); SetSymbolValue(STOP_FOR_GC_PENDING,NIL,thread); @@ -1178,7 +1204,7 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function) { #ifndef LISP_FEATURE_WIN32 - check_gc_signals_unblocked_in_sigset_or_lose + check_gc_signals_unblocked_or_lose (os_context_sigmask_addr(context)); #endif #if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) @@ -1482,10 +1508,9 @@ static volatile int sigaction_nodefer_works = -1; static void sigaction_nodefer_test_handler(int signal, siginfo_t *info, void *void_context) { - sigset_t empty, current; + sigset_t current; int i; - sigemptyset(&empty); - thread_sigmask(SIG_BLOCK, &empty, ¤t); + get_current_sigmask(¤t); /* There should be exactly two blocked signals: the two we added * to sa_mask when setting up the handler. NetBSD doesn't block * the signal we're handling when SA_NODEFER is set; Linux before @@ -1600,12 +1625,12 @@ install_handler(int signal, void handler(int, siginfo_t*, os_context_t*)) { #ifndef LISP_FEATURE_WIN32 struct sigaction sa; - sigset_t old, new; + sigset_t old; union interrupt_handler oldhandler; FSHOW((stderr, "/entering POSIX install_handler(%d, ..)\n", signal)); - thread_sigmask(SIG_BLOCK, &blockable_sigset, &old); + block_blockable_signals(0, &old); FSHOW((stderr, "/interrupt_low_level_handlers[signal]=%x\n", (unsigned int)interrupt_low_level_handlers[signal])); @@ -1696,7 +1721,15 @@ lisp_memory_fault_error(os_context_t *context, os_vm_address_t addr) */ current_memory_fault_address = addr; /* To allow debugging memory faults in signal handlers and such. */ - corruption_warning_and_maybe_lose("Memory fault at %x", addr); + corruption_warning_and_maybe_lose("Memory fault at %x (pc=%p, sp=%p)", + addr, + *os_context_pc_addr(context), +#ifdef ARCH_HAS_STACK_POINTER + *os_context_sp_addr(context) +#else + 0 +#endif + ); unblock_signals_in_context_and_maybe_warn(context); #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK arrange_return_to_lisp_function(context, @@ -1712,7 +1745,7 @@ unhandled_trap_error(os_context_t *context) { lispobj context_sap; fake_foreign_function_call(context); - unblock_gc_signals(); + unblock_gc_signals(0, 0); context_sap = alloc_sap(context); #ifndef LISP_FEATURE_WIN32 thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0); diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index 1d9f64f..4f2b097 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -26,6 +26,14 @@ /* FIXME: do not rely on NSIG being a multiple of 8 */ #define REAL_SIGSET_SIZE_BYTES ((NSIG/8)) +static inline void +sigcopyset(sigset_t *new, sigset_t *old) +{ + memcpy(new, old, REAL_SIGSET_SIZE_BYTES); +} + +extern void get_current_sigmask(sigset_t *sigset); + /* Set all deferrable signals into *s. */ extern void sigaddset_deferrable(sigset_t *s); /* Set all blockable signals into *s. */ @@ -37,25 +45,27 @@ extern sigset_t deferrable_sigset; extern sigset_t blockable_sigset; extern sigset_t gc_sigset; -extern void block_deferrable_signals(void); -extern void block_blockable_signals(void); -extern void unblock_deferrable_signals(void); -extern void unblock_gc_signals(void); -extern void unblock_signals_in_context_and_maybe_warn(os_context_t *context); +extern boolean deferrables_blocked_p(sigset_t *sigset); +extern boolean blockables_blocked_p(sigset_t *sigset); +extern boolean gc_signals_blocked_p(sigset_t *sigset); -extern boolean deferrables_blocked_in_sigset_p(sigset_t *sigset); -extern void check_deferrables_blocked_or_lose(void); -extern void check_blockables_blocked_or_lose(void); -extern void check_gc_signals_unblocked_or_lose(void); -extern void check_gc_signals_unblocked_in_sigset_or_lose(sigset_t *sigset); +extern void check_deferrables_blocked_or_lose(sigset_t *sigset); +extern void check_blockables_blocked_or_lose(sigset_t *sigset); +extern void check_gc_signals_blocked_or_lose(sigset_t *sigset); -extern void maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset); +extern void check_deferrables_unblocked_or_lose(sigset_t *sigset); +extern void check_blockables_unblocked_or_lose(sigset_t *sigset); +extern void check_gc_signals_unblocked_or_lose(sigset_t *sigset); -static inline void -sigcopyset(sigset_t *new, sigset_t *old) -{ - memcpy(new, old, REAL_SIGSET_SIZE_BYTES); -} +extern void block_deferrable_signals(sigset_t *where, sigset_t *old); +extern void block_blockable_signals(sigset_t *where, sigset_t *old); +extern void block_gc_signals(sigset_t *where, sigset_t *old); + +extern void unblock_deferrable_signals(sigset_t *where, sigset_t *old); +extern void unblock_blockable_signals(sigset_t *where, sigset_t *old); +extern void unblock_gc_signals(sigset_t *where, sigset_t *old); + +extern void maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset); /* maximum signal nesting depth * diff --git a/src/runtime/pthread-futex.c b/src/runtime/pthread-futex.c index a08eb80..cddcda9 100644 --- a/src/runtime/pthread-futex.c +++ b/src/runtime/pthread-futex.c @@ -227,12 +227,9 @@ futex_wait(int *lock_word, int oldval, long sec, unsigned long usec) { int ret, result; struct futex *futex; - sigset_t oldset, newset; + sigset_t oldset; struct timeval tv, *timeout; - sigemptyset(&newset); - sigaddset_deferrable(&newset); - again: if (sec < 0) timeout = NULL; @@ -245,7 +242,7 @@ again: timeout = &tv; } - pthread_sigmask(SIG_BLOCK, &newset, &oldset); + block_deferrable_signals(0, &oldset); futex = futex_get(lock_word); @@ -311,12 +308,9 @@ futex_wake(int *lock_word, int n) { int ret; struct futex *futex; - sigset_t newset, oldset; - - sigemptyset(&newset); - sigaddset_deferrable(&newset); + sigset_t oldset; - pthread_sigmask(SIG_BLOCK, &newset, &oldset); + block_deferrable_signals(0, &oldset); futex = futex_get(lock_word); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 03b519f..45f7eec 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -235,7 +235,7 @@ main(int argc, char *argv[], char *envp[]) const char *sbcl_home = getenv("SBCL_HOME"); interrupt_init(); - block_blockable_signals(); + block_blockable_signals(0, 0); setlocale(LC_ALL, ""); diff --git a/src/runtime/thread.c b/src/runtime/thread.c index 1da1108..84fb947 100644 --- a/src/runtime/thread.c +++ b/src/runtime/thread.c @@ -258,8 +258,8 @@ new_thread_trampoline(struct thread *th) int result, lock_ret; FSHOW((stderr,"/creating thread %lu\n", thread_self())); - check_deferrables_blocked_or_lose(); - check_gc_signals_unblocked_or_lose(); + check_deferrables_blocked_or_lose(0); + check_gc_signals_unblocked_or_lose(0); function = th->no_tls_value_marker; th->no_tls_value_marker = NO_TLS_VALUE_MARKER_WIDETAG; if(arch_os_thread_init(th)==0) { @@ -284,7 +284,7 @@ new_thread_trampoline(struct thread *th) result = funcall0(function); /* Block GC */ - block_blockable_signals(); + block_blockable_signals(0, 0); set_thread_state(th, STATE_DEAD); /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this @@ -514,7 +514,7 @@ boolean create_os_thread(struct thread *th,os_thread_t *kid_tid) /* Blocking deferrable signals is enough, no need to block * SIG_STOP_FOR_GC because the child process is not linked onto * all_threads until it's ready. */ - thread_sigmask(SIG_BLOCK, &deferrable_sigset, &oldset); + block_deferrable_signals(0, &oldset); #ifdef LOCK_CREATE_THREAD retcode = pthread_mutex_lock(&create_thread_lock); @@ -701,7 +701,7 @@ kill_safely(os_thread_t os_thread, int signal) struct thread *thread; /* pthread_kill is not async signal safe and we don't want to be * interrupted while holding the lock. */ - thread_sigmask(SIG_BLOCK, &deferrable_sigset, &oldset); + block_deferrable_signals(0, &oldset); pthread_mutex_lock(&all_threads_lock); for (thread = all_threads; thread; thread = thread->next) { if (thread->os_thread == os_thread) { diff --git a/src/runtime/x86-64-darwin-os.c b/src/runtime/x86-64-darwin-os.c index 046a125..bc42425 100644 --- a/src/runtime/x86-64-darwin-os.c +++ b/src/runtime/x86-64-darwin-os.c @@ -233,7 +233,7 @@ void signal_emulation_wrapper(x86_thread_state64_t *thread_state, build_fake_signal_context(context, thread_state, float_state); - block_blockable_signals(); + block_blockable_signals(0, 0); handler(signal, siginfo, context); diff --git a/src/runtime/x86-darwin-os.c b/src/runtime/x86-darwin-os.c index c657565..25f13b1 100644 --- a/src/runtime/x86-darwin-os.c +++ b/src/runtime/x86-darwin-os.c @@ -270,7 +270,7 @@ void signal_emulation_wrapper(x86_thread_state32_t *thread_state, build_fake_signal_context(context, thread_state, float_state); - block_blockable_signals(); + block_blockable_signals(0, 0); handler(signal, siginfo, context); diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index 9db5021..aeb807e 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -43,28 +43,30 @@ mutex)) (sb-alien:define-alien-routine "check_deferrables_blocked_or_lose" - void) + void + (where sb-alien:unsigned-long)) (sb-alien:define-alien-routine "check_deferrables_unblocked_or_lose" - void) + void + (where sb-alien:unsigned-long)) (with-test (:name (:interrupt-thread :deferrables-blocked)) (sb-thread:interrupt-thread sb-thread:*current-thread* (lambda () - (check-deferrables-blocked-or-lose)))) + (check-deferrables-blocked-or-lose 0)))) (with-test (:name (:interrupt-thread :deferrables-unblocked)) (sb-thread:interrupt-thread sb-thread:*current-thread* (lambda () (with-interrupts - (check-deferrables-unblocked-or-lose))))) + (check-deferrables-unblocked-or-lose 0))))) (with-test (:name (:interrupt-thread :nlx)) (catch 'xxx (sb-thread:interrupt-thread sb-thread:*current-thread* (lambda () - (check-deferrables-blocked-or-lose) + (check-deferrables-blocked-or-lose 0) (throw 'xxx nil)))) - (check-deferrables-unblocked-or-lose)) + (check-deferrables-unblocked-or-lose 0)) #-sb-thread (sb-ext:quit :unix-status 104) @@ -75,9 +77,9 @@ (sb-thread::get-spinlock spinlock) (sb-thread:interrupt-thread thread (lambda () - (check-deferrables-blocked-or-lose) + (check-deferrables-blocked-or-lose 0) (sb-thread::get-spinlock spinlock) - (check-deferrables-unblocked-or-lose) + (check-deferrables-unblocked-or-lose 0) (sb-ext:quit))) (sleep 1) (sb-thread::release-spinlock spinlock))) diff --git a/tests/timer.impure.lisp b/tests/timer.impure.lisp index 3f16fa1..2c1247a 100644 --- a/tests/timer.impure.lisp +++ b/tests/timer.impure.lisp @@ -14,9 +14,11 @@ (use-package :test-util) (sb-alien:define-alien-routine "check_deferrables_blocked_or_lose" - void) + void + (where sb-alien:unsigned-long)) (sb-alien:define-alien-routine "check_deferrables_unblocked_or_lose" - void) + void + (where sb-alien:unsigned-long)) (defun make-limited-timer (fn n &rest args) (let (timer) @@ -49,26 +51,26 @@ (with-test (:name (:timer :deferrables-blocked)) (make-and-schedule-and-wait (lambda () - (check-deferrables-blocked-or-lose)) + (check-deferrables-blocked-or-lose 0)) (random 0.1)) - (check-deferrables-unblocked-or-lose)) + (check-deferrables-unblocked-or-lose 0)) (with-test (:name (:timer :deferrables-unblocked)) (make-and-schedule-and-wait (lambda () (sb-sys:with-interrupts - (check-deferrables-unblocked-or-lose))) + (check-deferrables-unblocked-or-lose 0))) (random 0.1)) - (check-deferrables-unblocked-or-lose)) + (check-deferrables-unblocked-or-lose 0)) #-win32 (with-test (:name (:timer :deferrables-unblocked :unwind)) (catch 'xxx (make-and-schedule-and-wait (lambda () - (check-deferrables-blocked-or-lose) + (check-deferrables-blocked-or-lose 0) (throw 'xxx nil)) (random 0.1)) (sleep 1)) - (check-deferrables-unblocked-or-lose)) + (check-deferrables-unblocked-or-lose 0)) (defmacro raises-timeout-p (&body body) `(handler-case (progn (progn ,@body) nil) diff --git a/version.lisp-expr b/version.lisp-expr index 03710c9..56cd6de 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"1.0.26.14" +"1.0.26.15"