From edb227f57bcf629a9e8c3b8e6e1b37d644d8f217 Mon Sep 17 00:00:00 2001 From: Gabor Melis Date: Mon, 16 Feb 2009 21:49:30 +0000 Subject: [PATCH] 1.0.25.32: improvements to WITHOUT-GCING - implement it with only one UNWIND-PROTECT (about 30% faster) - add *IN-WITHOUT-GCING* - in maybe_defer_handler defer interrupts if we are in the racy part of WITHOUT-GCING, that is with interrupts enabled, gc allowed but still *IN-WITHOUT-GCING* - check more invariants --- NEWS | 1 + src/code/cold-init.lisp | 1 + src/code/globals.lisp | 2 +- src/code/sysmacs.lisp | 38 +++++++++++++++++++------------------- src/compiler/generic/parms.lisp | 1 + src/runtime/interrupt.c | 33 +++++++++++++++++++++++++++------ version.lisp-expr | 2 +- 7 files changed, 51 insertions(+), 27 deletions(-) diff --git a/NEWS b/NEWS index b47062d..efefafa 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ changes in sbcl-1.0.26 relative to 1.0.25: fault, etc. In the absence of --lose-on-corruption a warning is printed to stderr. * optimization: slightly faster gc on multithreaded builds + * optimization: faster WITHOUT-GCING * bug fix: real-time signals are not used anymore, so no more hanging when the system wide real-time signal queue gets full. diff --git a/src/code/cold-init.lisp b/src/code/cold-init.lisp index bcde5e7..c812dab 100644 --- a/src/code/cold-init.lisp +++ b/src/code/cold-init.lisp @@ -93,6 +93,7 @@ ;; *TYPE-SYSTEM-INITIALIZED-WHEN-BOUND* so that it doesn't need to ;; be explicitly set in order to be meaningful. (setf *after-gc-hooks* nil + *in-without-gcing* nil *gc-inhibit* t *gc-pending* nil #!+sb-thread *stop-for-gc-pending* #!+sb-thread nil diff --git a/src/code/globals.lisp b/src/code/globals.lisp index aac1ab2..96183e0 100644 --- a/src/code/globals.lisp +++ b/src/code/globals.lisp @@ -22,7 +22,7 @@ sb!debug:*stack-top-hint* *handler-clusters* *restart-clusters* - *gc-inhibit* *gc-pending* + *in-without-gcing* *gc-inhibit* *gc-pending* #!+sb-thread *stop-for-gc-pending* *software-interrupt-vector* *load-verbose* *load-print-stuff* *in-compilation-unit* diff --git a/src/code/sysmacs.lisp b/src/code/sysmacs.lisp index 60f18d7..986e7a8 100644 --- a/src/code/sysmacs.lisp +++ b/src/code/sysmacs.lisp @@ -19,16 +19,19 @@ (declare (optimize (safety 0) (speed 3))) (sb!vm::locked-symbol-global-value-add ',symbol-name ,delta))) -(defvar *gc-inhibit*) ; initialized in cold init +;;;; these are initialized in cold init + +(defvar *in-without-gcing*) +(defvar *gc-inhibit*) ;;; When the dynamic usage increases beyond this amount, the system ;;; notes that a garbage collection needs to occur by setting ;;; *GC-PENDING* to T. It starts out as NIL meaning nobody has figured ;;; out what it should be yet. -(defvar *gc-pending* nil) +(defvar *gc-pending*) #!+sb-thread -(defvar *stop-for-gc-pending* nil) +(defvar *stop-for-gc-pending*) (defmacro without-gcing (&body body) #!+sb-doc @@ -53,24 +56,21 @@ maintained." ,@body)) (if *gc-inhibit* (,without-gcing-body) - (without-interrupts - ;; We need to disable interrupts before disabling GC, so that - ;; signal handlers using locks don't accidentally try to grab - ;; them with GC inhibited. - ;; - ;; It would be nice to implement this with just a single UWP, but - ;; unfortunately it seems that it cannot be done: the naive - ;; solution of binding both *INTERRUPTS-ENABLED* and - ;; *GC-INHIBIT*, and checking for both pending GC and interrupts - ;; in the cleanup breaks if we have a GC pending, but no - ;; interrupts, and we receive an asynch unwind while checking for - ;; the pending GC: we unwind before handling the pending GC, and - ;; will be left running with further GCs blocked due to the GC - ;; pending flag. + ;; We need to disable interrupts before disabling GC, so + ;; that signal handlers using locks don't accidentally try + ;; to grab them with GC inhibited. + (let ((*in-without-gcing* t)) (unwind-protect - (let ((*gc-inhibit* t)) + (let* ((*allow-with-interrupts* nil) + (*interrupts-enabled* nil) + (*gc-inhibit* t)) (,without-gcing-body)) - (when (or *gc-pending* #!+sb-thread *stop-for-gc-pending*) + ;; This is not racy becuase maybe_defer_handler + ;; defers signals if *GC-INHIBIT* is NIL but there + ;; is a pending gc or stop-for-gc. + (when (or *interrupt-pending* + *gc-pending* + #!+sb-thread *stop-for-gc-pending*) (sb!unix::receive-pending-interrupt)))))))) ;;; EOF-OR-LOSE is a useful macro that handles EOF. diff --git a/src/compiler/generic/parms.lisp b/src/compiler/generic/parms.lisp index df1f733..c2691bd 100644 --- a/src/compiler/generic/parms.lisp +++ b/src/compiler/generic/parms.lisp @@ -57,6 +57,7 @@ sb!unix::*allow-with-interrupts* sb!unix::*interrupts-enabled* sb!unix::*interrupt-pending* + *in-without-gcing* *gc-inhibit* *gc-pending* #!-sb-thread diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index 2770d4d..b63f6fb 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -198,6 +198,22 @@ check_interrupts_enabled_or_lose(os_context_t *context) lose ("in pseudo atomic section\n"); } +/* Are we leaving WITH-GCING and already running with interrupts + * enabled, without the protection of *GC-INHIBIT* T and there is gc + * (or stop for gc) pending, but we haven't trapped yet? */ +int +in_leaving_without_gcing_race_p(struct thread *thread) +{ + return ((SymbolValue(IN_WITHOUT_GCING,thread) != NIL) && + (SymbolValue(INTERRUPTS_ENABLED,thread) != NIL) && + (SymbolValue(GC_INHIBIT,thread) == NIL) && + ((SymbolValue(GC_PENDING,thread) != NIL) +#if defined(LISP_FEATURE_SB_THREAD) + || (SymbolValue(STOP_FOR_GC_PENDING,thread) != NIL) +#endif + )); +} + /* Check our baroque invariants. */ void check_interrupt_context_or_lose(os_context_t *context) @@ -211,10 +227,11 @@ check_interrupt_context_or_lose(os_context_t *context) #if defined(LISP_FEATURE_GENCGC) && !defined(LISP_FEATURE_PPC) #if 0 int interrupts_enabled = (SymbolValue(INTERRUPTS_ENABLED,thread) != NIL); +#endif int gc_inhibit = (SymbolValue(GC_INHIBIT,thread) != NIL); int gc_pending = (SymbolValue(GC_PENDING,thread) == T); int pseudo_atomic_interrupted = get_pseudo_atomic_interrupted(thread); -#endif + int in_race_p = in_leaving_without_gcing_race_p(thread); /* In the time window between leaving the *INTERRUPTS-ENABLED* NIL * section and trapping, a SIG_STOP_FOR_GC would see the next * check fail, for this reason sig_stop_for_gc handler does not @@ -223,20 +240,19 @@ check_interrupt_context_or_lose(os_context_t *context) * triggered, too. */ #if 0 if (interrupt_deferred_p) - if (interrupts_enabled && !pseudo_atomic_interrupted) + if (!(!interrupts_enabled || pseudo_atomic_interrupted || in_race_p)) lose("Stray deferred interrupt."); #endif - /* Broken momentarily at the end of WITHOUT-GCING. */ #if 0 if (gc_pending) - if (!(pseudo_atomic_interrupted || gc_inhibit)) + if (!(pseudo_atomic_interrupted || gc_inhibit || in_race_p)) lose("GC_PENDING, but why?."); #if defined(LISP_FEATURE_SB_THREAD) { int stop_for_gc_pending = (SymbolValue(STOP_FOR_GC_PENDING,thread) != NIL); if (stop_for_gc_pending) - if (!(pseudo_atomic_interrupted || gc_inhibit)) + if (!(pseudo_atomic_interrupted || gc_inhibit || in_race_p)) lose("STOP_FOR_GC_PENDING, but why?."); } #endif @@ -723,8 +739,13 @@ maybe_defer_handler(void *handler, struct interrupt_data *data, /* If interrupts are disabled then INTERRUPT_PENDING is set and * not PSEDUO_ATOMIC_INTERRUPTED. This is important for a pseudo * atomic section inside a WITHOUT-INTERRUPTS. + * + * Also, if in_leaving_without_gcing_race_p then + * interrupt_handle_pending is going to be called soon, so + * stashing the signal away is safe. */ - if (SymbolValue(INTERRUPTS_ENABLED,thread) == NIL) { + if ((SymbolValue(INTERRUPTS_ENABLED,thread) == NIL) || + in_leaving_without_gcing_race_p(thread)) { store_signal_data_for_later(data,handler,signal,info,context); SetSymbolValue(INTERRUPT_PENDING, T,thread); FSHOW_SIGNAL((stderr, diff --git a/version.lisp-expr b/version.lisp-expr index 3395220..71d5467 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.31" +"1.0.25.32" -- 1.7.10.4