X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fgc.lisp;h=fbd4e4bed87d84c758e0ece56a500e48c795ab06;hb=bfb7c2d573bacfd9c5f3f243b7c1589f81f11406;hp=e0bc9de472faa6d9355a8bdf3c9728bfb3c70952;hpb=3358092524adbaecaa483d6510fb3d7031441ccb;p=sbcl.git diff --git a/src/code/gc.lisp b/src/code/gc.lisp index e0bc9de..fbd4e4b 100644 --- a/src/code/gc.lisp +++ b/src/code/gc.lisp @@ -10,46 +10,53 @@ ;;;; files for more information. (in-package "SB!KERNEL") - -(file-comment - "$Header$") ;;;; DYNAMIC-USAGE and friends (declaim (special sb!vm:*read-only-space-free-pointer* - sb!vm:*static-space-free-pointer*)) + sb!vm:*static-space-free-pointer*)) (eval-when (:compile-toplevel :execute) - (sb!xc:defmacro def-c-var-frob (lisp-fun c-var-name) - `(progn - #!-sb-fluid (declaim (inline ,lisp-fun)) - (defun ,lisp-fun () - (sb!alien:extern-alien ,c-var-name (sb!alien:unsigned 32)))))) + (sb!xc:defmacro def-c-var-fun (lisp-fun c-var-name) + `(defun ,lisp-fun () + (sb!alien:extern-alien ,c-var-name (sb!alien:unsigned 32))))) -(def-c-var-frob sb!vm:control-stack-start "control_stack") -#!+x86 (def-c-var-frob control-stack-end "control_stack_end") -(def-c-var-frob sb!vm:binding-stack-start "binding_stack") +#!-sb-fluid +(declaim (inline current-dynamic-space-start)) +#!+gencgc +(defun current-dynamic-space-start () sb!vm:dynamic-space-start) +#!-gencgc +(def-c-var-fun current-dynamic-space-start "current_dynamic_space") -#!-sb-fluid (declaim (inline dynamic-usage)) -(def-c-var-frob dynamic-usage "bytes_allocated") +#!-sb-fluid +(declaim (inline dynamic-usage)) +#!+gencgc +(def-c-var-fun dynamic-usage "bytes_allocated") +#!-gencgc +(defun dynamic-usage () + (the (unsigned-byte 32) + (- (sb!sys:sap-int (sb!c::dynamic-space-free-pointer)) + (current-dynamic-space-start)))) (defun static-space-usage () - (- (* sb!vm:*static-space-free-pointer* sb!vm:word-bytes) + (- (* sb!vm:*static-space-free-pointer* sb!vm:n-word-bytes) sb!vm:static-space-start)) (defun read-only-space-usage () - (- (* sb!vm::*read-only-space-free-pointer* sb!vm:word-bytes) + (- (* sb!vm::*read-only-space-free-pointer* sb!vm:n-word-bytes) sb!vm:read-only-space-start)) (defun control-stack-usage () - #!-x86 (- (sb!sys:sap-int (sb!c::control-stack-pointer-sap)) - (control-stack-start)) - #!+x86 (- (control-stack-end) - (sb!sys:sap-int (sb!c::control-stack-pointer-sap)))) + #!-stack-grows-downward-not-upward + (- (sb!sys:sap-int (sb!c::control-stack-pointer-sap)) + (sb!sys:sap-int (sb!di::descriptor-sap sb!vm:*control-stack-start*))) + #!+stack-grows-downward-not-upward + (- (sb!sys:sap-int (sb!di::descriptor-sap sb!vm:*control-stack-end*)) + (sb!sys:sap-int (sb!c::control-stack-pointer-sap)))) (defun binding-stack-usage () (- (sb!sys:sap-int (sb!c::binding-stack-pointer-sap)) - (sb!vm:binding-stack-start))) + (sb!sys:sap-int (sb!di::descriptor-sap sb!vm:*binding-stack-start*)))) ;;;; ROOM @@ -59,31 +66,37 @@ (format t "Static space usage is: ~10:D bytes.~%" (static-space-usage)) (format t "Control stack usage is: ~10:D bytes.~%" (control-stack-usage)) (format t "Binding stack usage is: ~10:D bytes.~%" (binding-stack-usage)) + #!+sb-thread + (format t + "Control and binding stack usage is for the current thread only.~%") (format t "Garbage collection is currently ~:[enabled~;DISABLED~].~%" - *gc-inhibit*)) + *gc-inhibit*)) (defun room-intermediate-info () (room-minimal-info) (sb!vm:memory-usage :count-spaces '(:dynamic) - :print-spaces t - :cutoff 0.05s0 - :print-summary nil)) + :print-spaces t + :cutoff 0.05f0 + :print-summary nil)) (defun room-maximal-info () - (room-minimal-info) - (sb!vm:memory-usage :count-spaces '(:static :dynamic)) - (sb!vm:instance-usage :dynamic :top-n 10) - (sb!vm:instance-usage :static :top-n 10)) + ;; FIXME: SB!VM:INSTANCE-USAGE calls suppressed until bug 344 is fixed + (room-intermediate-info) + ;; old way, could be restored when bug 344 fixed: + ;;x (room-minimal-info) + ;;x (sb!vm:memory-usage :count-spaces '(:static :dynamic)) + ;;x (sb!vm:instance-usage :dynamic :top-n 10) + ;;x (sb!vm:instance-usage :static :top-n 10) + ) (defun room (&optional (verbosity :default)) #!+sb-doc - "Prints to *STANDARD-OUTPUT* information about the state of internal + "Print to *STANDARD-OUTPUT* information about the state of internal storage and its management. The optional argument controls the - verbosity of ROOM. If it is T, ROOM prints out a maximal amount of + verbosity of output. If it is T, ROOM prints out a maximal amount of information. If it is NIL, ROOM prints out a minimal amount of information. If it is :DEFAULT or it is not supplied, ROOM prints out - an intermediate amount of information. See also VM:MEMORY-USAGE and - VM:INSTANCE-USAGE for finer report control." + an intermediate amount of information." (fresh-line) (ecase verbosity ((t) @@ -96,320 +109,147 @@ ;;;; GET-BYTES-CONSED -;;; internal state -(defvar *last-bytes-in-use* nil) -(defvar *total-bytes-consed* 0) -(declaim (type (or index null) *last-bytes-in-use*)) -(declaim (type integer *total-bytes-consed*)) +;;; the total number of bytes freed so far (including any freeing +;;; which goes on in PURIFY) +;;; +;;; (We save this so that we can calculate the total number of bytes +;;; ever allocated by adding this to the number of bytes currently +;;; allocated and never freed.) +(declaim (type unsigned-byte *n-bytes-freed-or-purified*)) +(defvar *n-bytes-freed-or-purified* 0) +(defun gc-reinit () + (gc-on) + (gc) + (setf *n-bytes-freed-or-purified* 0 + ;; See comment in interr.lisp + *heap-exhausted-error-condition* (make-condition 'heap-exhausted-error))) (declaim (ftype (function () unsigned-byte) get-bytes-consed)) (defun get-bytes-consed () #!+sb-doc - "Returns the number of bytes consed since the first time this function - was called. The first time it is called, it returns zero." - (declare (optimize (speed 3) (safety 0))) - (cond ((null *last-bytes-in-use*) - (setq *last-bytes-in-use* (dynamic-usage)) - (setq *total-bytes-consed* 0)) - (t - (let ((bytes (dynamic-usage))) - (incf *total-bytes-consed* - (the index (- bytes *last-bytes-in-use*))) - (setq *last-bytes-in-use* bytes)))) - *total-bytes-consed*) + "Return the number of bytes consed since the program began. Typically +this result will be a consed bignum, so if you have an application (e.g. +profiling) which can't tolerate the overhead of consing bignums, you'll +probably want either to hack in at a lower level (as the code in the +SB-PROFILE package does), or to design a more microefficient interface +and submit it as a patch." + (+ (dynamic-usage) + *n-bytes-freed-or-purified*)) -;;;; variables and constants - -;;; the default value of *BYTES-CONSED-BETWEEN-GCS* and *GC-TRIGGER* -(defconstant default-bytes-consed-between-gcs 2000000) - -;;; This variable is the user-settable variable that specifies the -;;; minimum amount of dynamic space which must be consed before a GC -;;; will be triggered. -;;; -;;; Unlike CMU CL, we don't export this variable. (There's no need to, since -;;; the BYTES-CONSED-BETWEEN-GCS function is SETFable.) -(defvar *bytes-consed-between-gcs* default-bytes-consed-between-gcs - #!+sb-doc - "This number specifies the minimum number of bytes of dynamic space - that must be consed before the next GC will occur.") -(declaim (type index *bytes-consed-between-gcs*)) - ;;;; GC hooks -;;; These variables are a list of functions which are run before and -;;; after garbage collection occurs. -(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.") -(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.") - -;;; This hook is invoked whenever SUB-GC intends to GC (unless the GC -;;; was explicitly forced by calling SB!EXT:GC). If the hook function -;;; returns NIL then the GC procedes; otherwise, the GC is inhibited and -;;; *GC-INHIBIT* and *NEED-TO-COLLECT-GARBAGE* are left bound to T. -;;; Presumably someone will call GC-ON later to collect the garbage. -(defvar *gc-inhibit-hook* nil - #!+sb-doc - "Should be bound to a function or NIL. If it is a function, this - function should take one argument, the current amount of dynamic - usage. The function should return NIL if garbage collection should - continue and non-NIL if it should be inhibited. Use with caution.") - -(defvar *gc-verbose* nil ; (actually initialized in cold init) - #!+sb-doc - "Should low-level GC functions produce verbose diagnostic output?") - -(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.") - -(defvar *gc-run-time* 0 - #!+sb-doc - "The total CPU time spent doing garbage collection (as reported by - GET-INTERNAL-RUN-TIME.)") - -(declaim (type index *gc-run-time*)) - -;;; Internal trigger. When the dynamic usage increases beyond this -;;; amount, the system notes that a garbage collection needs to occur by -;;; setting *NEED-TO-COLLECT-GARBAGE* to T. It starts out as NIL meaning -;;; nobody has figured out what it should be yet. -(defvar *gc-trigger* nil) +(defvar *after-gc-hooks* nil + "Called after each garbage collection, except for garbage collections +triggered during thread exits. In a multithreaded environment these hooks may +run in any thread.") -(declaim (type (or index null) *gc-trigger*)) - -;;; On the RT, we store the GC trigger in a ``static'' symbol instead of -;;; letting magic C code handle it. It gets initialized by the startup -;;; code. The X86 port defines this here because it uses the `ibmrt' -;;; feature in the C code for allocation and binding stack access and -;;; a lot of stuff wants this INTERNAL_GC_TRIGGER available as well. -#!+(or ibmrt x86) -(defvar sb!vm::*internal-gc-trigger*) - -;;;; The following specials are used to control when garbage collection -;;;; occurs. - -;;; When non-NIL, inhibits garbage collection. -(defvar *gc-inhibit*) ; initialized in cold init - -;;; This flag is used to prevent recursive entry into the garbage -;;; collector. -(defvar *already-maybe-gcing*) ; initialized in cold init - -;;; When T, indicates that the dynamic usage has exceeded the value -;;; *GC-TRIGGER*. -(defvar *need-to-collect-garbage* nil) ; initialized in cold init - -(defun default-gc-notify-before (notify-stream bytes-in-use) - (declare (type stream notify-stream)) - (format notify-stream - "~&; GC is beginning with ~:D bytes in use.~%" - bytes-in-use) - (finish-output notify-stream)) -(defparameter *gc-notify-before* #'default-gc-notify-before - #!+sb-doc - "This function bound to this variable is invoked before GC'ing (unless - *GC-NOTIFY-STREAM* is NIL) with the value of *GC-NOTIFY-STREAM* and - current amount of dynamic usage (in bytes). It should notify the - user that the system is going to GC.") - -(defun default-gc-notify-after (notify-stream - bytes-retained - bytes-freed - new-trigger) - (declare (type stream notify-stream)) - (format notify-stream - "~&; GC has finished with ~:D bytes in use (~:D bytes freed).~%" - bytes-retained - bytes-freed) - (format notify-stream - "~&; The new GC trigger is ~:D bytes.~%" - new-trigger) - (finish-output notify-stream)) -(defparameter *gc-notify-after* #'default-gc-notify-after - #!+sb-doc - "The function bound to this variable is invoked after GC'ing (unless - *GC-VERBOSE* is NIL) with the value of *GC-NOTIFY-STREAM*, - the amount of dynamic usage (in bytes) now free, the number of - bytes freed by the GC, and the new GC trigger threshold. The function - should notify the user that the system has finished GC'ing.") ;;;; internal GC -(sb!alien:def-alien-routine collect-garbage sb!c-call:int - #!+gencgc (last-gen sb!c-call:int)) - -(sb!alien:def-alien-routine set-auto-gc-trigger sb!c-call:void - (dynamic-usage sb!c-call:unsigned-long)) +(sb!alien:define-alien-routine collect-garbage sb!alien:int + (#!+gencgc last-gen #!-gencgc ignore sb!alien:int)) -(sb!alien:def-alien-routine clear-auto-gc-trigger sb!c-call:void) +#!+sb-thread +(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 ())) -;;; This variable contains the function that does the real GC. This is -;;; for low-level GC experimentation. Do not touch it if you do not -;;; know what you are doing. -(defvar *internal-gc* #'collect-garbage) ;;;; SUB-GC -;;; Used to carefully invoke hooks. -(eval-when (:compile-toplevel :execute) - (sb!xc:defmacro carefully-funcall (function &rest args) - `(handler-case (funcall ,function ,@args) - (error (cond) - (warn "(FUNCALL ~S~{ ~S~}) lost:~%~A" ',function ',args cond) - nil)))) - -;;; SUB-GC decides when and if to do a garbage collection. The -;;; VERBOSE-P flag controls whether or not the notify functions are -;;; called. The FORCE-P flags controls if a GC should occur even if -;;; the dynamic usage is not greater than *GC-TRIGGER*. +;;; 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. 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 ;;; +;;; This is different from the behaviour in 0.7 and earlier: it no +;;; longer decides whether to GC based on thresholds. If you call +;;; SUB-GC you will definitely get a GC either now or when the +;;; WITHOUT-GCING is over + ;;; For GENCGC all generations < GEN will be GC'ed. -;;; -;;; FIXME: The VERBOSE-P stuff is no longer used. -(defun sub-gc (&key (verbose-p *gc-verbose*) force-p #!+gencgc (gen 0)) - (/show0 "entering SUB-GC") - (unless *already-maybe-gcing* - (/show0 "not *ALREADY-MAYBE-GCING*") - (let* ((*already-maybe-gcing* t) - (start-time (get-internal-run-time)) - (pre-gc-dyn-usage (dynamic-usage))) - (unless (integerp (symbol-value '*bytes-consed-between-gcs*)) - ;; The noise w/ symbol-value above is to keep the compiler - ;; from optimizing the test away because of the type declaim - ;; for *bytes-consed-between-gcs*. - ;; - ;; FIXME: I'm inclined either to get rid of the DECLAIM or to - ;; trust it, instead of doing this weird hack. It's not - ;; particularly trustable, since (SETF - ;; *BYTES-CONSED-BETWEEN-GCS* 'SEVEN) works. But it's also not - ;; very nice to have the type of the variable specified in two - ;; places which can (and in CMU CL 2.4.8 did, INTEGER vs. - ;; INDEX) drift apart. So perhaps we should just add a note to - ;; the variable documentation for *BYTES-CONSED-BETWEEN-GCS* - ;; that it must be an INDEX, and remove the DECLAIM. Or we - ;; could make a SETFable (BYTES-CONSED-BETWEEN-GCS) function - ;; and enforce the typing that way. And in fact the SETFable - ;; function already exists, so all we need do is make the - ;; variable private, and then we can trust the DECLAIM. - (warn "The value of *BYTES-CONSED-BETWEEN-GCS*, ~S, is not an ~ - integer. Resetting it to ~D." - *bytes-consed-between-gcs* - default-bytes-consed-between-gcs) - (setf *bytes-consed-between-gcs* default-bytes-consed-between-gcs)) - (when (and *gc-trigger* (> pre-gc-dyn-usage *gc-trigger*)) - (/show0 "setting *NEED-TO-COLLECT-GARBAGE* to T") - (setf *need-to-collect-garbage* t)) - (when (or force-p - (and *need-to-collect-garbage* (not *gc-inhibit*))) - (/show0 "Evidently we ought to collect garbage..") - (when (and (not force-p) - *gc-inhibit-hook* - (carefully-funcall *gc-inhibit-hook* pre-gc-dyn-usage)) - (/show0 "..but we're inhibited.") - (setf *gc-inhibit* t) - (return-from sub-gc nil)) - ;; KLUDGE: Wow, we really mask interrupts all the time we're - ;; collecting garbage? That seems like a long time.. -- WHN 19991129 - (without-interrupts - ;; FIXME: We probably shouldn't do this evil thing to - ;; *STANDARD-OUTPUT* in a binding which is wrapped around - ;; calls to user-settable GC hook functions. - (let ((*standard-output* *terminal-io*)) - (when *gc-notify-stream* - (/show0 "doing the *GC-NOTIFY-BEFORE* thing") - (if (streamp *gc-notify-stream*) - (carefully-funcall *gc-notify-before* - *gc-notify-stream* - pre-gc-dyn-usage) - (warn - "*GC-NOTIFY-STREAM* is set, but not a STREAM -- ignored."))) - (dolist (hook *before-gc-hooks*) - (/show0 "doing a hook from *BEFORE-GC-HOOKS*") - (carefully-funcall hook)) - (when *gc-trigger* - (clear-auto-gc-trigger)) - (/show0 "FUNCALLing *INTERNAL-GC*, one way or another") - #!-gencgc (funcall *internal-gc*) - ;; FIXME: This EQ test is pretty gross. Among its other - ;; nastinesses, it looks as though it could break if we - ;; recompile COLLECT-GARBAGE. - #!+gencgc (if (eq *internal-gc* #'collect-garbage) - (funcall *internal-gc* gen) - (funcall *internal-gc*)) - (/show0 "back from FUNCALL to *INTERNAL-GC*") - (let* ((post-gc-dyn-usage (dynamic-usage)) - (bytes-freed (- pre-gc-dyn-usage post-gc-dyn-usage))) - (when *last-bytes-in-use* - (incf *total-bytes-consed* - (- pre-gc-dyn-usage *last-bytes-in-use*)) - (setq *last-bytes-in-use* post-gc-dyn-usage)) - (setf *need-to-collect-garbage* nil) - (let ((new-gc-trigger (+ post-gc-dyn-usage - *bytes-consed-between-gcs*))) - (setf *gc-trigger* new-gc-trigger)) - (set-auto-gc-trigger *gc-trigger*) - (dolist (hook *after-gc-hooks*) - (/show0 "doing a hook from *AFTER-GC--HOOKS*") - ;; FIXME: This hook should be called with the - ;; same kind of information as *GC-NOTIFY-AFTER*. - ;; In particular, it would be nice for the - ;; hook function to be able to adjust *GC-TRIGGER* - ;; intelligently to e.g. 108% of total memory usage. - (carefully-funcall hook)) - (when *gc-notify-stream* - (/show0 "doing the *GC-NOTIFY-AFTER* thing") - (if (streamp *gc-notify-stream*) - (carefully-funcall *gc-notify-after* - *gc-notify-stream* - post-gc-dyn-usage - bytes-freed - *gc-trigger*) - (warn - "*GC-NOTIFY-STREAM* is set, but not a stream -- ignored."))))) - (/show0 "scrubbing control stack") - (scrub-control-stack))) - (/show0 "updating *GC-RUN-TIME*") - (incf *gc-run-time* (- (get-internal-run-time) - start-time)))) - ;; FIXME: should probably return (VALUES), here and in RETURN-FROM - (/show "returning from tail of SUB-GC") - nil) -;;; This routine is called by the allocation miscops to decide whether -;;; a GC should occur. The argument, OBJECT, is the newly allocated -;;; object which must be returned to the caller. -(defun maybe-gc (&optional object) - (sub-gc) - object) +(defvar *already-in-gc* + (sb!thread:make-mutex :name "GC lock") "ID of thread running SUB-GC") + +(defun sub-gc (&key (gen 0)) + (unless (eq sb!thread:*current-thread* + (sb!thread::mutex-value *already-in-gc*)) + ;; With gencgc, unless *GC-PENDING* every allocation in this + ;; function triggers another gc, potentially exceeding maximum + ;; interrupt nesting. + (setq *gc-pending* t) + (unless *gc-inhibit* + (sb!thread:with-mutex (*already-in-gc*) + (let ((old-usage (dynamic-usage)) + (new-usage 0)) + (unsafe-clear-roots) + ;; We need to disable interrupts for GC, but we also want + ;; to run as little as possible without them. + (without-interrupts + (gc-stop-the-world) + (let ((start-time (get-internal-run-time))) + (collect-garbage gen) + (incf *gc-run-time* + (- (get-internal-run-time) start-time))) + (setf *gc-pending* nil + new-usage (dynamic-usage)) + (gc-start-the-world)) + ;; Interrupts re-enabled, but still inside the mutex. + ;; In a multithreaded environment the other threads will + ;; see *n-b-f-o-p* change a little late, but that's OK. + (let ((freed (- old-usage new-usage))) + ;; GENCGC occasionally reports negative here, but the + ;; current belief is that it is part of the normal order + ;; of things and not a bug. + (when (plusp freed) + (incf *n-bytes-freed-or-purified* freed))))) + ;; Outside the mutex, these may cause another GC. FIXME: it can + ;; potentially exceed maximum interrupt nesting by triggering + ;; GCs. + ;; + ;; Can that be avoided by having the finalizers and hooks run only + ;; from the outermost SUB-GC? + ;; + ;; KLUDGE: Don't run the hooks in GC's triggered by dying threads, + ;; so that user-code never runs with + ;; (thread-alive-p *current-thread*) => nil + ;; The long-term solution will be to keep a separate thread for + ;; finalizers and after-gc hooks. + (when (sb!thread:thread-alive-p sb!thread:*current-thread*) + (run-pending-finalizers) + (dolist (hook *after-gc-hooks*) + (handler-case + (funcall hook) + (error (c) + (warn "Error calling after-GC hook ~S:~% ~A" hook c)))))))) ;;; This is the user-advertised garbage collection function. -;;; -;;; KLUDGE: GC shouldn't have different parameters depending on what -;;; garbage collector we use. -- WHN 19991020 -#!-gencgc -(defun gc (&optional (verbose-p *gc-verbose*)) - #!+sb-doc - "Initiates a garbage collection. VERBOSE-P controls - whether or not GC statistics are printed." - (sub-gc :verbose-p verbose-p :force-p t)) -#!+gencgc -(defun gc (&key (verbose *gc-verbose*) (gen 0) (full nil)) - #!+sb-doc - "Initiates a garbage collection. VERBOSE controls whether or not GC - statistics are printed. GEN controls the number of generations to garbage - collect." - ;; FIXME: The bare 6 here (corresponding to a bare 6 in - ;; the gencgc.c sources) is nasty. - (sub-gc :verbose-p verbose :force-p t :gen (if full 6 gen))) +(defun gc (&key (gen 0) (full nil) &allow-other-keys) + #!+(and sb-doc gencgc) + "Initiate a garbage collection. GEN controls the number of generations + to garbage collect." + #!+(and sb-doc (not gencgc)) + "Initiate a garbage collection. GEN may be provided for compatibility with + generational garbage collectors, but is ignored in this implementation." + (sub-gc :gen (if full 6 gen))) + +(defun unsafe-clear-roots () + ;; KLUDGE: Do things in an attempt to get rid of extra roots. Unsafe + ;; as having these cons more then we have space left leads to huge + ;; badness. + (scrub-control-stack) + ;; FIXME: CTYPE-OF-CACHE-CLEAR isn't thread-safe. + #!-sb-thread + (ctype-of-cache-clear)) + ;;;; auxiliary functions @@ -417,42 +257,33 @@ #!+sb-doc "Return the amount of memory that will be allocated before the next garbage collection is initiated. This can be set with SETF." - *bytes-consed-between-gcs*) + (sb!alien:extern-alien "bytes_consed_between_gcs" + (sb!alien:unsigned 32))) + (defun (setf bytes-consed-between-gcs) (val) - ;; FIXME: Shouldn't this (and the DECLAIM for the underlying variable) - ;; be for a strictly positive number type, e.g. - ;; (AND (INTEGER 1) FIXNUM)? (declare (type index val)) - (let ((old *bytes-consed-between-gcs*)) - (setf *bytes-consed-between-gcs* val) - (when *gc-trigger* - (setf *gc-trigger* (+ *gc-trigger* (- val old))) - (cond ((<= (dynamic-usage) *gc-trigger*) - (clear-auto-gc-trigger) - (set-auto-gc-trigger *gc-trigger*)) - (t - (sb!sys:scrub-control-stack) - (sub-gc))))) - val) - + (setf (sb!alien:extern-alien "bytes_consed_between_gcs" + (sb!alien:unsigned 32)) + val)) + +(declaim (inline maybe-handle-pending-gc)) +(defun maybe-handle-pending-gc () + (when (and (not *gc-inhibit*) + (or #!+sb-thread *stop-for-gc-pending* + *gc-pending*)) + (sb!unix::receive-pending-interrupt))) + +;;; These work both regardless of whether we're inside WITHOUT-GCING +;;; or not. (defun gc-on () #!+sb-doc - "Enables the garbage collector." + "Enable the garbage collector." (setq *gc-inhibit* nil) - (when *need-to-collect-garbage* - (sub-gc)) + (maybe-handle-pending-gc) nil) (defun gc-off () #!+sb-doc - "Disables the garbage collector." + "Disable the garbage collector." (setq *gc-inhibit* t) nil) - -;;;; initialization stuff - -(defun gc-cold-init-or-reinit () - (when *gc-trigger* - (if (< *gc-trigger* (dynamic-usage)) - (sub-gc) - (set-auto-gc-trigger *gc-trigger*))))