From 89aafeff1876325edaacdd6b294e4ef065980bf2 Mon Sep 17 00:00:00 2001 From: Gabor Melis Date: Mon, 16 Feb 2009 21:54:06 +0000 Subject: [PATCH] 1.0.25.35: check that gc signals are unblocked ... when alloc() is called and when calling into Lisp. --- doc/internals/signals.texinfo | 4 ++++ src/runtime/alloc.c | 6 ++++++ src/runtime/breakpoint.c | 2 ++ src/runtime/funcall.c | 29 +++++++++++++++++++++-------- src/runtime/interrupt.c | 21 ++++++++------------- version.lisp-expr | 2 +- 6 files changed, 42 insertions(+), 22 deletions(-) diff --git a/doc/internals/signals.texinfo b/doc/internals/signals.texinfo index 33c0adf..e5cfceb 100644 --- a/doc/internals/signals.texinfo +++ b/doc/internals/signals.texinfo @@ -145,6 +145,10 @@ derive the rule: in a @code{WITHOUT-GCING} form (or pseudo atomic for that matter) never wait for another thread that's not in @code{WITHOUT-GCING}. +Somewhat of a special case, it is enforced by the runtime that +@code{SIG_STOP_FOR_GC} and @code{SIG_RESUME_FROM_GC} always unblocked +when we might trigger a gc (i.e. on alloc or calling into Lisp). + @subsection Calling user code For the reasons above, calling user code, i.e. functions passed in, or diff --git a/src/runtime/alloc.c b/src/runtime/alloc.c index f42be24..dc4f5f2 100644 --- a/src/runtime/alloc.c +++ b/src/runtime/alloc.c @@ -40,6 +40,12 @@ pa_alloc(int bytes, int page_type_flag) lispobj *result; struct thread *th = arch_os_get_current_thread(); + /* SIG_STOP_FOR_GC needs to be enabled before we can call lisp: + * 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(); + /* FIXME: OOAO violation: see arch_pseudo_* */ set_pseudo_atomic_atomic(th); result = general_alloc(bytes, page_type_flag); diff --git a/src/runtime/breakpoint.c b/src/runtime/breakpoint.c index 18f96d8..5dfa9a4 100644 --- a/src/runtime/breakpoint.c +++ b/src/runtime/breakpoint.c @@ -130,6 +130,7 @@ void handle_breakpoint(os_context_t *context) fake_foreign_function_call(context); + unblock_gc_signals(); context_sap = alloc_sap(context); code = find_code(context); @@ -154,6 +155,7 @@ void *handle_fun_end_breakpoint(os_context_t *context) fake_foreign_function_call(context); + unblock_gc_signals(); context_sap = alloc_sap(context); code = find_code(context); codeptr = (struct code *)native_pointer(code); diff --git a/src/runtime/funcall.c b/src/runtime/funcall.c index e364ec2..186435c 100644 --- a/src/runtime/funcall.c +++ b/src/runtime/funcall.c @@ -18,10 +18,23 @@ #include "sbcl.h" #include "runtime.h" #include "globals.h" +#include "os.h" +#include "interrupt.h" /* This is implemented in assembly language and called from C: */ extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs); +static inline lispobj +safe_call_into_lisp(lispobj fun, lispobj *args, int nargs) +{ + /* SIG_STOP_FOR_GC needs to be enabled before we can call lisp: + * 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(); + return call_into_lisp(fun, args, nargs); +} + #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* These functions are an interface to the Lisp call-in facility. * Since this is C we can know nothing about the calling environment. @@ -38,14 +51,14 @@ funcall0(lispobj function) lispobj *args = NULL; FSHOW((stderr, "/entering funcall0(0x%lx)\n", (long)function)); - return call_into_lisp(function, args, 0); + return safe_call_into_lisp(function, args, 0); } lispobj funcall1(lispobj function, lispobj arg0) { lispobj args[1]; args[0] = arg0; - return call_into_lisp(function, args, 1); + return safe_call_into_lisp(function, args, 1); } lispobj @@ -54,7 +67,7 @@ funcall2(lispobj function, lispobj arg0, lispobj arg1) lispobj args[2]; args[0] = arg0; args[1] = arg1; - return call_into_lisp(function, args, 2); + return safe_call_into_lisp(function, args, 2); } lispobj @@ -64,7 +77,7 @@ funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2) args[0] = arg0; args[1] = arg1; args[2] = arg2; - return call_into_lisp(function, args, 3); + return safe_call_into_lisp(function, args, 3); } #else @@ -74,7 +87,7 @@ funcall0(lispobj function) { lispobj *args = current_control_stack_pointer; - return call_into_lisp(function, args, 0); + return safe_call_into_lisp(function, args, 0); } lispobj @@ -85,7 +98,7 @@ funcall1(lispobj function, lispobj arg0) current_control_stack_pointer += 1; args[0] = arg0; - return call_into_lisp(function, args, 1); + return safe_call_into_lisp(function, args, 1); } lispobj @@ -97,7 +110,7 @@ funcall2(lispobj function, lispobj arg0, lispobj arg1) args[0] = arg0; args[1] = arg1; - return call_into_lisp(function, args, 2); + return safe_call_into_lisp(function, args, 2); } lispobj @@ -110,6 +123,6 @@ funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2) args[1] = arg1; args[2] = arg2; - return call_into_lisp(function, args, 3); + return safe_call_into_lisp(function, args, 3); } #endif diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index d44e53c..ff62022 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -489,6 +489,7 @@ interrupt_internal_error(os_context_t *context, boolean continuable) /* Allocate the SAP object while the interrupts are still * disabled. */ + unblock_gc_signals(); context_sap = alloc_sap(context); #ifndef LISP_FEATURE_WIN32 @@ -693,21 +694,12 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) * Yeah, but non-gencgc platforms don't really wrap allocation * in PA. MG - 2005-08-29 */ - lispobj info_sap,context_sap = alloc_sap(context); - info_sap = alloc_sap(info); + lispobj info_sap, context_sap; /* Leave deferrable signals blocked, the handler itself will * allow signals again when it sees fit. */ -#ifdef LISP_FEATURE_SB_THREAD - { - sigset_t unblock; - sigemptyset(&unblock); - sigaddset(&unblock, SIG_STOP_FOR_GC); -#ifdef SIG_RESUME_FROM_GC - sigaddset(&unblock, SIG_RESUME_FROM_GC); -#endif - thread_sigmask(SIG_UNBLOCK, &unblock, 0); - } -#endif + unblock_gc_signals(); + context_sap = alloc_sap(context); + info_sap = alloc_sap(info); FSHOW_SIGNAL((stderr,"/calling Lisp-level handler\n")); @@ -966,6 +958,8 @@ extern void call_into_lisp_tramp(void); void arrange_return_to_lisp_function(os_context_t *context, lispobj function) { + check_gc_signals_unblocked_in_sigset_or_lose + (os_context_sigmask_addr(context)); #if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) void * fun=native_pointer(function); void *code = &(((struct simple_fun *) fun)->code); @@ -1460,6 +1454,7 @@ unhandled_trap_error(os_context_t *context) { lispobj context_sap; fake_foreign_function_call(context); + unblock_gc_signals(); context_sap = alloc_sap(context); #ifndef LISP_FEATURE_WIN32 thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0); diff --git a/version.lisp-expr b/version.lisp-expr index 9c15bfe..4b69e45 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.25.34" +"1.0.25.35" -- 1.7.10.4