0.9.2.9: thread objects
[sbcl.git] / src / code / gc.lisp
index 7c548fd..1acfa9c 100644 (file)
                  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)))))
 
+#!-sb-fluid
+(declaim (inline current-dynamic-space-start))
+#!+gencgc
+(defun current-dynamic-space-start () sb!vm:dynamic-space-start)
 #!-gencgc
-(progn
-  ;; This is called once per PROFILEd function call, so it's worth a
-  ;; little possible space cost to reduce its time cost.
-  #!-sb-fluid
-  (declaim (inline current-dynamic-space-start))
-  (def-c-var-frob current-dynamic-space-start "current_dynamic_space"))
+(def-c-var-fun current-dynamic-space-start "current_dynamic_space")
 
 #!-sb-fluid
-(declaim (inline dynamic-usage)) ; to reduce PROFILEd call overhead
+(declaim (inline dynamic-usage))
 #!+gencgc
-(def-c-var-frob dynamic-usage "bytes_allocated")
+(def-c-var-fun dynamic-usage "bytes_allocated")
 #!-gencgc
 (defun dynamic-usage ()
   (the (unsigned-byte 32)
                      :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
 ;;; allocated and never freed.)
 (declaim (type unsigned-byte *n-bytes-freed-or-purified*))
 (defvar *n-bytes-freed-or-purified* 0)
-(push (lambda ()
-       (setf *n-bytes-freed-or-purified* 0))
-      ;; KLUDGE: It's probably not quite safely right either to do
-      ;; this in *BEFORE-SAVE-INITIALIZATIONS* (since consing, or even
-      ;; worse, something which depended on (GET-BYTES-CONSED), might
-      ;; happen after that) or in *AFTER-SAVE-INITIALIZATIONS*. But
-      ;; it's probably not a big problem, and there seems to be no
-      ;; other obvious time to do it. -- WHN 2001-07-30
-      *after-save-initializations*)
+(defun gc-reinit ()
+  (gc-on)
+  (gc)
+  (setf *n-bytes-freed-or-purified* 0))
 
 (declaim (ftype (function () unsigned-byte) get-bytes-consed))
 (defun get-bytes-consed ()
@@ -140,17 +136,9 @@ and submit it as a patch."
 \f
 ;;;; GC hooks
 
-(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 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 are run with interrupts disabled and all other threads
-  paused.  They should take no arguments.")
+(defvar *after-gc-hooks* nil
+  "Called after each garbage collection. In a multithreaded
+environment these hooks may run in any thread.")
 
 ;;;; The following specials are used to control when garbage
 ;;;; collection occurs.
@@ -201,14 +189,6 @@ and submit it as a patch."
 \f
 ;;;; SUB-GC
 
-;;; This is 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 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
@@ -227,25 +207,44 @@ and submit it as a patch."
 (defvar *already-in-gc* 
   (sb!thread:make-mutex :name "GC lock") "ID of thread running SUB-GC")
 
-(defun sub-gc (&key (gen 0) &aux (pre-gc-dynamic-usage (dynamic-usage)))
-  (let ((me (sb!thread:current-thread-id)))
-    (when (eql (sb!thread::mutex-value *already-in-gc*) me) 
-      (return-from sub-gc nil))
+(defun sub-gc (&key (gen 0))
+  (unless (eq sb!thread:*current-thread*
+              (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*)
-      (loop
-       (sb!thread:with-mutex (*already-in-gc*)
-        (unless *need-to-collect-garbage* (return-from sub-gc nil))
-        (without-interrupts
-         (gc-stop-the-world)
-         (collect-garbage gen)
-         (incf *n-bytes-freed-or-purified*
-               (max 0 (- pre-gc-dynamic-usage (dynamic-usage))))
-         (scrub-control-stack)
-         (setf *need-to-collect-garbage* nil)
-         (dolist (h *after-gc-hooks*) (carefully-funcall h))
-         (gc-start-the-world))
-        (sb!thread::reap-dead-threads))))))
+      (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)))))
+      ;; 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
+           (funcall hook)
+         (error (c)
+           (warn "Error calling after GC hook ~S:~%  ~S" hook c)))))))
 
 ;;; This is the user-advertised garbage collection function.
 (defun gc (&key (gen 0) (full nil) &allow-other-keys)
@@ -257,6 +256,15 @@ and submit it as a patch."
   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))
+
 \f
 ;;;; auxiliary functions
 
@@ -273,6 +281,9 @@ and submit it as a patch."
                               (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.
 (defun gc-on ()
   #!+sb-doc
   "Enable the garbage collector."
@@ -286,4 +297,3 @@ and submit it as a patch."
   "Disable the garbage collector."
   (setq *gc-inhibit* 1)
   nil)
-