X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fgc.lisp;h=0e6018461a83552219a80de0dc4bcdf16fdd4ce6;hb=1b650be8b800cf96e2c268ae317fb26d0bf36827;hp=f3dacccbcd22e1dba6d3afb5b8a3438e2f19182b;hpb=ebdf67c1da1884d5def43062a97174f28fcb6a2c;p=sbcl.git diff --git a/src/code/gc.lisp b/src/code/gc.lisp index f3daccc..0e60184 100644 --- a/src/code/gc.lisp +++ b/src/code/gc.lisp @@ -143,19 +143,14 @@ and submit it as a patch." (defvar *before-gc-hooks* nil ; actually initialized in cold init #!+sb-doc "A list of functions that are called before garbage collection occurs. - The functions should take no arguments.") + The functions are run with interrupts disabled and all other threads + paused. They should take no arguments.") (defvar *after-gc-hooks* nil ; actually initialized in cold init #!+sb-doc "A list of functions that are called after garbage collection occurs. - The functions should take no arguments.") - -(defvar *gc-notify-stream* nil ; (actually initialized in cold init) - #!+sb-doc - "When non-NIL, this must be a STREAM; and the functions bound to - *GC-NOTIFY-BEFORE* and *GC-NOTIFY-AFTER* are called with the - STREAM value before and after a garbage collection occurs - respectively.") + The functions are run with interrupts disabled and all other threads + paused. They should take no arguments.") (defvar *gc-run-time* 0 #!+sb-doc @@ -204,9 +199,14 @@ and submit it as a patch." (#!+gencgc last-gen #!-gencgc ignore sb!alien:int)) #!+sb-thread -(def-c-var-frob gc-thread-pid "gc_thread_pid") +(progn + (sb!alien:define-alien-routine gc-stop-the-world sb!alien:void) + (sb!alien:define-alien-routine gc-start-the-world sb!alien:void)) +#!-sb-thread +(progn + (defun gc-stop-the-world ()) + (defun gc-start-the-world ())) - ;;;; SUB-GC @@ -220,7 +220,8 @@ and submit it as a patch." ;;; SUB-GC does a garbage collection. This is called from three places: ;;; (1) The C runtime will call here when it detects that we've consed -;;; enough to exceed the gc trigger threshold +;;; enough to exceed the gc trigger threshold. This is done in +;;; alloc() for gencgc or interrupt_maybe_gc() for cheneygc ;;; (2) The user may request a collection using GC, below ;;; (3) At the end of a WITHOUT-GCING section, we are called if ;;; *NEED-TO-COLLECT-GARBAGE* is true @@ -232,37 +233,27 @@ and submit it as a patch." ;;; For GENCGC all generations < GEN will be GC'ed. -#!+sb-thread -(defun sub-gc (&key (gen 0) &aux (pre-gc-dynamic-usage (dynamic-usage))) - (setf *need-to-collect-garbage* t) - (when (zerop *gc-inhibit*) - (setf (sb!alien:extern-alien "maybe_gc_pending" (sb!alien:unsigned 32)) - (1+ gen)) - (if (zerop (sb!alien:extern-alien "stop_the_world" (sb!alien:unsigned 32))) - (sb!unix:unix-kill (gc-thread-pid) :SIGALRM)) - (loop - (when (zerop - (sb!alien:extern-alien "maybe_gc_pending" (sb!alien:unsigned 32))) - (return nil))) - (incf *n-bytes-freed-or-purified* - (max 0 (- pre-gc-dynamic-usage (dynamic-usage)))) - (setf *need-to-collect-garbage* nil) - (scrub-control-stack)) - (values)) - -#!-sb-thread (defvar *already-in-gc* nil "System is running SUB-GC") -#!-sb-thread +(defvar *gc-mutex* (sb!thread:make-mutex :name "GC Mutex")) + (defun sub-gc (&key (gen 0) &aux (pre-gc-dynamic-usage (dynamic-usage))) (when *already-in-gc* (return-from sub-gc nil)) (setf *need-to-collect-garbage* t) (when (zerop *gc-inhibit*) - (let ((*already-in-gc* t)) - (without-interrupts (collect-garbage gen)) - (incf *n-bytes-freed-or-purified* - (max 0 (- pre-gc-dynamic-usage (dynamic-usage)))) - (setf *need-to-collect-garbage* nil)) - (scrub-control-stack)) + (sb!thread:with-recursive-lock (*gc-mutex*) + (let ((*already-in-gc* t)) + (without-interrupts + (gc-stop-the-world) + (dolist (h *before-gc-hooks*) + (carefully-funcall h)) + (collect-garbage gen) + (incf *n-bytes-freed-or-purified* + (max 0 (- pre-gc-dynamic-usage (dynamic-usage)))) + (setf *need-to-collect-garbage* nil) + (dolist (h *after-gc-hooks*) + (carefully-funcall h)) + (gc-start-the-world))) + (scrub-control-stack))) (values))