1.0.16.19: cleanups motivated by clisp host-2
[sbcl.git] / src / code / gc.lisp
index 6daa745..e6abbb1 100644 (file)
@@ -14,7 +14,7 @@
 ;;;; 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-fun (lisp-fun c-var-name)
@@ -24,7 +24,7 @@
 #!-sb-fluid
 (declaim (inline current-dynamic-space-start))
 #!+gencgc
-(defun current-dynamic-space-spart () sb!vm:dynamic-space-start)
+(defun current-dynamic-space-start () sb!vm:dynamic-space-start)
 #!-gencgc
 (def-c-var-fun current-dynamic-space-start "current_dynamic_space")
 
 (defun control-stack-usage ()
   #!-stack-grows-downward-not-upward
   (- (sb!sys:sap-int (sb!c::control-stack-pointer-sap))
-     (sb!vm:fixnumize sb!vm:*control-stack-start*))
+     (sb!sys:sap-int (sb!di::descriptor-sap sb!vm:*control-stack-start*)))
   #!+stack-grows-downward-not-upward
-  (- (sb!vm:fixnumize sb!vm:*control-stack-end*)
+  (- (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:fixnumize sb!vm:*binding-stack-start*)))
+     (sb!sys:sap-int (sb!di::descriptor-sap sb!vm:*binding-stack-start*))))
 \f
 ;;;; ROOM
 
   (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
+          "Control and binding stack usage is for the current thread only.~%")
   (format t "Garbage collection is currently ~:[enabled~;DISABLED~].~%"
-         (> *gc-inhibit* 0)))
+          *gc-inhibit*))
 
 (defun room-intermediate-info ()
   (room-minimal-info)
   (sb!vm:memory-usage :count-spaces '(:dynamic)
-                     :print-spaces t
-                     :cutoff 0.05f0
-                     :print-summary nil))
+                      :print-spaces t
+                      :cutoff 0.05f0
+                      :print-summary nil))
 
 (defun room-maximal-info ()
   ;; FIXME: SB!VM:INSTANCE-USAGE calls suppressed until bug 344 is fixed
 (defun gc-reinit ()
   (gc-on)
   (gc)
-  (setf *n-bytes-freed-or-purified* 0))
+  (setf *n-bytes-freed-or-purified* 0
+        *gc-run-time* 0
+        ;; See comment in interr.lisp
+        *heap-exhausted-error-condition* (make-condition 'heap-exhausted-error)))
 
-(declaim (ftype (function () unsigned-byte) get-bytes-consed))
+(declaim (ftype (sfunction () unsigned-byte) get-bytes-consed))
 (defun get-bytes-consed ()
   #!+sb-doc
   "Return the number of bytes consed since the program began. Typically
@@ -137,40 +140,10 @@ and submit it as a patch."
 ;;;; GC hooks
 
 (defvar *after-gc-hooks* nil
-  "Called after each garbage collection. In a multithreaded
-environment these hooks may run in any thread.")
+  "Called after each garbage collection, except for garbage collections
+triggered during thread exits. In a multithreaded environment these hooks may
+run in any thread.")
 
-;;;; The following specials are used to control when garbage
-;;;; collection occurs.
-
-;;; 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.
-;;;
-;;; FIXME: *GC-TRIGGER* seems to be denominated in bytes, not words.
-;;; And limiting it to INDEX is fairly reasonable in order to avoid
-;;; bignum arithmetic on every allocation, and to minimize the need
-;;; for thought about weird gotchas of the GC-control mechanism itself
-;;; consing as it operates. But as of sbcl-0.7.5, 512Mbytes of memory
-;;; costs $54.95 at Fry's in Dallas but cheap consumer 64-bit machines
-;;; are still over the horizon, so gratuitously limiting our heap size
-;;; to FIXNUM bytes seems fairly stupid. It'd be reasonable to
-;;; (1) allow arbitrary UNSIGNED-BYTE values of *GC-TRIGGER*, or
-;;; (2) redenominate this variable in words instead of bytes, postponing
-;;;     the problem to heaps which exceed 50% of the machine's address
-;;;     space, or even
-;;; (3) redemoninate this variable in CONS-sized two-word units,
-;;;     allowing it to cover the entire memory space at the price of
-;;;     possible loss of clarity.
-;;; (And whatever is done, it'd also be good to rename the variable so
-;;; that it's clear what unit it's denominated in.)
-(declaim (type (or index null) *gc-trigger*))
-(defvar *gc-trigger* nil)
-
-;;; When T, indicates that a GC should have happened but did not due to 
-;;; *GC-INHIBIT*. 
-(defvar *need-to-collect-garbage* nil) ; initialized in cold init
 \f
 ;;;; internal GC
 
@@ -190,7 +163,7 @@ environment these hooks may run in any thread.")
 ;;;; SUB-GC
 
 ;;; 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 
+;;; (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
@@ -204,43 +177,78 @@ environment these hooks may run in any thread.")
 
 ;;; For GENCGC all generations < GEN will be GC'ed.
 
-(defvar *already-in-gc* 
+(defvar *already-in-gc*
   (sb!thread:make-mutex :name "GC lock") "ID of thread running SUB-GC")
 
+;;; A unique GC id. This is supplied for code that needs to detect
+;;; whether a GC has happened since some earlier point in time. For
+;;; example:
+;;;
+;;;   (let ((epoch *gc-epoch*))
+;;;      ...
+;;;      (unless (eql epoch *gc-epoch)
+;;;        ....))
+;;;
+;;; This isn't just a fixnum counter since then we'd have theoretical
+;;; problems when exactly 2^29 GCs happen between epoch
+;;; comparisons. Unlikely, but the cost of using a cons instead is too
+;;; small to measure. -- JES, 2007-09-30
+(declaim (type cons *gc-epoch*))
+(defvar *gc-epoch* (cons nil nil))
+
 (defun sub-gc (&key (gen 0))
-  (unless (eql (sb!thread:current-thread-id)
-              (sb!thread::mutex-value *already-in-gc*))
-    (setf *need-to-collect-garbage* t)
-    (when (zerop *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)       
-           (collect-garbage gen)
-           (setf *need-to-collect-garbage* 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)))
-         (sb!thread::reap-dead-threads)))
-      ;; Outside the mutex, these may cause another GC.
-      (run-pending-finalizers)
-      (dolist (hook *after-gc-hooks*)
-       (handler-case
-           (funcall hook)
-         (error (c)
-           (warn "Error calling after GC hook ~S:~%  ~S" hook c)))))))
+  (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. If *GC-INHIBIT* is not true, however,
+    ;; there is no guarantee that we would ever check for pending
+    ;; GC -- so in that case we must first disable interrupts, which
+    ;; needs to be done for GC anyways...
+    (cond (*gc-inhibit*
+           (setf *gc-pending* t))
+          (t
+           (without-interrupts
+             (setf *gc-pending* t)
+             (sb!thread:with-mutex (*already-in-gc*)
+               (let ((old-usage (dynamic-usage))
+                     (new-usage 0))
+                 (unsafe-clear-roots)
+
+                 (gc-stop-the-world)
+                 (let ((start-time (get-internal-run-time)))
+                   (collect-garbage gen)
+                   (setf *gc-epoch* (cons nil nil))
+                   (incf *gc-run-time*
+                         (- (get-internal-run-time) start-time)))
+                 (setf *gc-pending* nil
+                       new-usage (dynamic-usage))
+                 (gc-start-the-world)
+
+                 ;; 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, interrupts enabled: 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)
+             (call-hooks "after-GC" *after-gc-hooks* :on-error :warn))))))
 
 ;;; This is the user-advertised garbage collection function.
 (defun gc (&key (gen 0) (full nil) &allow-other-keys)
@@ -257,6 +265,9 @@ environment these hooks may run in any thread.")
   ;; as having these cons more then we have space left leads to huge
   ;; badness.
   (scrub-control-stack)
+  ;; Power cache of the bignum printer: drops overly large bignums and
+  ;; removes duplicate entries.
+  (scrub-power-cache)
   ;; FIXME: CTYPE-OF-CACHE-CLEAR isn't thread-safe.
   #!-sb-thread
   (ctype-of-cache-clear))
@@ -269,28 +280,32 @@ environment these hooks may run in any thread.")
   "Return the amount of memory that will be allocated before the next garbage
    collection is initiated. This can be set with SETF."
   (sb!alien:extern-alien "bytes_consed_between_gcs"
-                        (sb!alien:unsigned 32)))
+                         (sb!alien:unsigned 32)))
 
 (defun (setf bytes-consed-between-gcs) (val)
   (declare (type index val))
   (setf (sb!alien:extern-alien "bytes_consed_between_gcs"
-                              (sb!alien:unsigned 32))
-       val))
-
-;;; FIXME: Aren't these utterly wrong if called inside WITHOUT-GCING?
-;;; Unless something that works there too can be deviced this fact
-;;; should be documented.
+                               (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
   "Enable the garbage collector."
-  (setq *gc-inhibit* 0)
-  (when *need-to-collect-garbage*
-    (sub-gc))
+  (setq *gc-inhibit* nil)
+  (maybe-handle-pending-gc)
   nil)
 
 (defun gc-off ()
   #!+sb-doc
   "Disable the garbage collector."
-  (setq *gc-inhibit* 1)
+  (setq *gc-inhibit* t)
   nil)
-