Update of /cvsroot/sbcl/sbcl/src/code
In directory sc8-pr-cvs1:/tmp/cvs-serv2903/src/code
Modified Files:
gc.lisp target-thread.lisp
Log Message:
0.8.3.1
Merge stop_the_world branch: a new scheme for stopping threads
during GC, that avoids the use of ptrace and lets any of the
threads stop any of the others. This is a summary log entry:
see branch commits for details
New C functions maybe_defer_handler and run_deferred_handler,
which encapsulate a lot of the "is it safe to run this handler
now? no, ok, copy its siginfo somewhere safe and do it later"
cruft that's presently done ad hoc.
Stack scavenging now looks for esp in the most recent
interrupt context for each thread. Requires that threads
save said interrupt contexts in sig_stop_for_gc_handler
Clean up some compiler warnings in gencgc.c
Lisp-level changes: approximately a reversion to old-style (or
single-threaded) GC. Haven't actually added the gc hooks back
in yet, but now there's at least a place for them to go.
Lock around SUB-GC to remove window that may allow two threads
to attempt to collect at once.
WITHOUT-INTERRUPTS around SUB-GC to protect c-level spinlocks
used in gc_{stop,start}_the_world
(C-level spinlocks are just integers manipulated by get_spinlock(),
release_spinlock(). There's no unwind-protect or anything
involved in their use, so a thread interrupted when it's
holding one of these will continue to hold it)
Remove #if 0 from around the copying of sigmask in
undo_fake_foreign_function_call. Replace sizeof(sigmask_t)
with an expression involving the value of NSIG and the rash
assumption that sigset_t is a bitmask.
Moved get_spinlock into foo-arch.h and made it static inline.
Added release_spinlock for parity
Delete irritating message from sigcont_handler
New test cases
Index: gc.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/gc.lisp,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- gc.lisp 29 May 2003 16:14:44 -0000 1.48
+++ gc.lisp 25 Aug 2003 21:00:01 -0000 1.49
@@ -204,9 +204,14 @@
(#!+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 +225,8 @@
;;; 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 +238,25 @@
;;; 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)
+ ;; XXX run before-gc-hooks
+ (collect-garbage gen)
+ (incf *n-bytes-freed-or-purified*
+ (max 0 (- pre-gc-dynamic-usage (dynamic-usage))))
+ (setf *need-to-collect-garbage* nil)
+ ;; XXX run after-gc-hooks
+ (gc-start-the-world)))
+ (scrub-control-stack)))
(values))
Index: target-thread.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/target-thread.lisp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- target-thread.lisp 16 Aug 2003 20:38:40 -0000 1.9
+++ target-thread.lisp 25 Aug 2003 21:00:01 -0000 1.10
@@ -125,8 +125,7 @@
(setf (waitqueue-data queue)
(delete pid (waitqueue-data queue))))))
-;;; this should probably only be called while holding the queue spinlock.
-;;; not sure
+;;; this should only be called while holding the queue spinlock.
(defun signal-queue-head (queue)
(let ((p (car (waitqueue-data queue))))
(when p (sb!unix:unix-kill p :sigcont))))
|