From 83388ef649bc59c983042c082fb23797ca088406 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Sun, 29 Apr 2007 15:51:01 +0000 Subject: [PATCH] 1.0.5.4: signal handler consing causing GCs * Skip GC attempt if interrupts are enabled but GC signals are blocked in the context we would restore. This can happen at least when a signal handler conses while GC signals are blocked, so what we take a PendingInterrupt trap while in the original handler. --- NEWS | 3 +++ src/runtime/gc-common.c | 13 +++++++++++-- src/runtime/interrupt.c | 21 --------------------- version.lisp-expr | 2 +- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/NEWS b/NEWS index ca11a2a00..bf7203721 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ changes in sbcl-1.0.6 relative to sbcl-1.0.5: * bug fix: GETHASH, (SETF GETHASH), CLRHASH and REMHASH are now interrupt safe. + * bug fix: GC race condition occasionally resulting in crashes with + the error message "SIG_STOP_FOR_GC blocked at a bad place" has been + fixed. changes in sbcl-1.0.5 relative to sbcl-1.0.4: * incompatible change: removed writer methods for host-ent-name, diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c index 418244824..02321c26e 100644 --- a/src/runtime/gc-common.c +++ b/src/runtime/gc-common.c @@ -2468,8 +2468,17 @@ maybe_gc(os_context_t *context) */ #ifndef LISP_FEATURE_WIN32 if(SymbolValue(INTERRUPTS_ENABLED,thread)!=NIL) { - thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0); - check_gc_signals_unblocked_or_lose(); + sigset_t *context_sigmask = os_context_sigmask_addr(context); + /* What if the context we'd like to restore has GC signals + * blocked? Just skip the GC: we can't set GC_PENDING, because + * that would block the next attempt, and we don't know when + * we'd next check for it -- and it's hard to be sure that + * unblocking would be safe. */ + if (sigismember(context_sigmask,SIG_STOP_FOR_GC)) { + undo_fake_foreign_function_call(context); + return 1; + } + thread_sigmask(SIG_SETMASK, context_sigmask, 0); } else unblock_gc_signals(); diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index 20dfab259..08aba572b 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -136,27 +136,6 @@ check_blockables_blocked_or_lose(void) } void -check_gc_signals_unblocked_or_lose(void) -{ -#ifdef LISP_FEATURE_SB_THREAD -# if !defined(LISP_FEATURE_WIN32) - /* Get the current sigmask, by blocking the empty set. */ - sigset_t empty,current; - sigemptyset(&empty); - thread_sigmask(SIG_BLOCK, &empty, ¤t); - if (sigismember(¤t, SIG_STOP_FOR_GC)) - lose("SIG_STOP_FOR_GC blocked in thread %p at a bad place\n", - arch_os_get_current_thread()); -# if defined(SIG_RESUME_FROM_GC) - if (sigismember(¤t, SIG_RESUME_FROM_GC)) - lose("SIG_RESUME_FROM_GC blocked in thread %p at a bad place\n", - arch_os_get_current_thread()); -# endif -# endif -#endif -} - -void unblock_gc_signals(void) { #ifdef LISP_FEATURE_SB_THREAD diff --git a/version.lisp-expr b/version.lisp-expr index 729077b46..3da9d7f95 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.5.3" +"1.0.5.4" -- 2.11.4.GIT