From 5e4205cf17c3a04d4a8f6aed55c28b5a338caf47 Mon Sep 17 00:00:00 2001 From: Gabor Melis Date: Thu, 9 Jun 2005 08:32:29 +0000 Subject: [PATCH] 0.9.1.33: * gencgc: don't flood the system with gc interrupts if not absolutely necessary * fix compilation on freebsd --- src/code/gc.lisp | 7 ++++++- src/compiler/x86-64/parms.lisp | 2 ++ src/compiler/x86/parms.lisp | 2 ++ src/runtime/gencgc.c | 45 ++++++++++++++++++++++++---------------- src/runtime/interrupt.c | 2 +- version.lisp-expr | 2 +- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/code/gc.lisp b/src/code/gc.lisp index af6a759..f90150f 100644 --- a/src/code/gc.lisp +++ b/src/code/gc.lisp @@ -210,6 +210,9 @@ environment these hooks may run in any thread.") (defun sub-gc (&key (gen 0)) (unless (eql (sb!thread:current-thread-id) (sb!thread::mutex-value *already-in-gc*)) + ;; With gencgc, unless *NEED-TO-COLLECT-GARBAGE* every allocation + ;; in this function triggers another gc, potentially exceeding + ;; maximum interrupt nesting. (setf *need-to-collect-garbage* t) (when (zerop *gc-inhibit*) (sb!thread:with-mutex (*already-in-gc*) @@ -234,7 +237,9 @@ environment these hooks may run in any thread.") (when (plusp freed) (incf *n-bytes-freed-or-purified* freed))) (sb!thread::reap-dead-threads))) - ;; Outside the mutex, these may cause another GC. + ;; Outside the mutex, these may cause another GC. FIXME: it can + ;; potentially exceed maximum interrupt nesting by triggering + ;; GCs. (run-pending-finalizers) (dolist (hook *after-gc-hooks*) (handler-case diff --git a/src/compiler/x86-64/parms.lisp b/src/compiler/x86-64/parms.lisp index 740c173..d03dc9b 100644 --- a/src/compiler/x86-64/parms.lisp +++ b/src/compiler/x86-64/parms.lisp @@ -200,6 +200,8 @@ *control-stack-start* *control-stack-end* + *need-to-collect-garbage* + ;; the floating point constants *fp-constant-0d0* *fp-constant-1d0* diff --git a/src/compiler/x86/parms.lisp b/src/compiler/x86/parms.lisp index a380896..6c8850e 100644 --- a/src/compiler/x86/parms.lisp +++ b/src/compiler/x86/parms.lisp @@ -306,6 +306,8 @@ *control-stack-start* *control-stack-end* + *need-to-collect-garbage* + ;; the floating point constants *fp-constant-0d0* *fp-constant-1d0* diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index b7666e7..45a3a1e 100644 --- a/src/runtime/gencgc.c +++ b/src/runtime/gencgc.c @@ -4142,24 +4142,33 @@ alloc(long nbytes) * we should GC in the near future */ if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) { - /* set things up so that GC happens when we finish the PA - * section. We only do this if there wasn't a pending handler - * already, in case it was a gc. If it wasn't a GC, the next - * allocation will get us back to this point anyway, so no harm done - */ - sigset_t new_mask,old_mask; - sigemptyset(&new_mask); - sigaddset_blockable(&new_mask); - sigprocmask(SIG_BLOCK,&new_mask,&old_mask); - - struct interrupt_data *data=th->interrupt_data; - if((!data->pending_handler) && - maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0)) { - /* Leave the signals blocked just as if it was deferred - * the normal way and set the pending_mask. */ - sigcopyset(&(data->pending_mask),&old_mask); - } else { - sigprocmask(SIG_SETMASK,&old_mask,0); + struct thread *thread=arch_os_get_current_thread(); + /* Don't flood the system with interrupts if the need to gc is + * already noted. This can happen for example when SUB-GC + * allocates or after a gc triggered in a WITHOUT-GCING. */ + if (SymbolValue(NEED_TO_COLLECT_GARBAGE,thread) == NIL) { + /* set things up so that GC happens when we finish the PA + * section. We only do this if there wasn't a pending + * handler already, in case it was a gc. If it wasn't a + * GC, the next allocation will get us back to this point + * anyway, so no harm done + */ + sigset_t new_mask,old_mask; + sigemptyset(&new_mask); + sigaddset_blockable(&new_mask); + sigprocmask(SIG_BLOCK,&new_mask,&old_mask); + + struct interrupt_data *data=th->interrupt_data; + if((!data->pending_handler) && + maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0)) { + /* Leave the signals blocked just as if it was + * deferred the normal way and set the + * pending_mask. */ + sigcopyset(&(data->pending_mask),&old_mask); + SetSymbolValue(NEED_TO_COLLECT_GARBAGE,T,thread); + } else { + sigprocmask(SIG_SETMASK,&old_mask,0); + } } } new_obj = gc_alloc_with_region(nbytes,0,region,0); diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index d23df7b..aa2a23f 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -106,9 +106,9 @@ inline static void check_blockables_blocked_or_lose() { /* Get the current sigmask, by blocking the empty set. */ sigset_t empty,current; + int i; sigemptyset(&empty); sigprocmask(SIG_BLOCK, &empty, ¤t); - int i; for(i=0;i