Update of /cvsroot/sbcl/sbcl/src/code
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv4605/src/code
signal.lisp sysmacs.lisp timer.lisp
220.127.116.11: interrupt and GC issues
* Add WITHOUT-INTERRUPTS to WITHOUT-GCING.
* Warn if WITH-INTERRUPTS nested in WITHOUT-GCING.
* Make sure that SIG_STOP_FOR_GC and SIG_RESUME_FROM_GC are enabled on
threaded builds before calling into SUB-GC from the runtime.
* Better WITHOUT-GCING, WITHOUT-INTERRUPTS, and WITH-INTERRUPTS
* Internals documentation about POSIX signal safety rules.
RCS file: /cvsroot/sbcl/sbcl/src/code/signal.lisp,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- signal.lisp 14 Jul 2005 16:30:38 -0000 1.16
+++ signal.lisp 26 Mar 2007 10:30:30 -0000 1.17
@@ -42,7 +42,11 @@
(sb!xc:defmacro without-interrupts (&body body)
- "Execute BODY in a context impervious to interrupts."
+ "Execute BODY with all deferrable interrupts deferred. Deferrable interrupts
+include most blockable POSIX signals, and SB-THREAD:INTERRUPT-THREAD. Does not
+interfere with garbage collection, and unlike in many traditional Lisps using
+userspace threads, in SBCL WITHOUT-INTERRUPTS does not inhibit scheduling of
(let ((name (gensym "WITHOUT-INTERRUPTS-BODY-")))
`(flet ((,name () ,@body))
@@ -66,12 +70,16 @@
(sb!xc:defmacro with-interrupts (&body body)
"Allow interrupts while executing BODY. As interrupts are normally allowed,
- this is only useful inside a WITHOUT-INTERRUPTS."
+this is only useful inside a SB-SYS:WITHOUT-INTERRUPTS. Signals a runtime
+warning if used inside the dynamic countour of SB-SYS:WITHOUT-GCING."
(let ((name (gensym)))
`(flet ((,name () ,@body))
- (let ((*interrupts-enabled* t))
- (when *interrupt-pending*
+ (when sb!kernel:*gc-inhibit*
+ (warn "Re-enabling interrupts while GC is inhibited."))
+ (let ((*interrupts-enabled* t))
+ (when *interrupt-pending*
RCS file: /cvsroot/sbcl/sbcl/src/code/sysmacs.lisp,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- sysmacs.lisp 18 Nov 2005 12:28:40 -0000 1.26
+++ sysmacs.lisp 26 Mar 2007 10:30:30 -0000 1.27
@@ -32,14 +32,26 @@
(defmacro without-gcing (&body body)
- "Executes the forms in the body without doing a garbage
-collection. It inhibits both automatically and explicitly triggered
-gcs. Finally, upon leaving the BODY if gc is not inhibited it runs the
-pending gc. Similarly, if gc is triggered in another thread then it
-waits until gc is enabled in this thread."
+ "Executes the forms in the body without doing a garbage collection. It
+inhibits both automatically and explicitly triggered collections. Finally,
+upon leaving the BODY if gc is not inhibited it runs the pending gc.
+Similarly, if gc is triggered in another thread then it waits until gc is
+enabled in this thread.
+Implies SB-SYS:WITHOUT-INTERRUPTS for BODY, and causes any nested
+SB-SYS:WITH-INTERRUPTS to signal a warning during execution of the BODY.
+Should be used with great care, and not at all in multithreaded application
+code: Any locks that are ever acquired while GC is inhibited need to be always
+held with GC inhibited to prevent deadlocks: if T1 holds the lock and is
+stopped for GC while T2 is waiting for the lock inside WITHOUT-GCING the
+system will be deadlocked. Since SBCL does not currently document its internal
+locks, application code can never be certain that this invariant is
- (let ((*gc-inhibit* t))
+ (let ((*gc-inhibit* t))
;; the test is racy, but it can err only on the overeager side
RCS file: /cvsroot/sbcl/sbcl/src/code/timer.lisp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- timer.lisp 18 Mar 2007 19:30:25 -0000 1.8
+++ timer.lisp 26 Mar 2007 10:30:30 -0000 1.9
@@ -361,8 +361,26 @@
(defmacro sb!ext:with-timeout (expires &body body)
- "Execute the body, asynchronously interrupting it and signalling a
-TIMEOUT condition after at least EXPIRES seconds have passed."
+ "Execute the body, asynchronously interrupting it and signalling a TIMEOUT
+condition after at least EXPIRES seconds have passed.
+Note that it is never safe to unwind from an asynchronous condition. Consider:
+ (defun call-with-foo (function)
+ (let (foo)
+ (setf foo (get-foo))
+ (funcall function foo))
+ (when foo
+ (release-foo foo)))))
+If TIMEOUT occurs after GET-FOO has executed, but before the assignment, then
+RELEASE-FOO will be missed. While individual sites like this can be made proof
+against asynchronous unwinds, this doesn't solve the fundamental issue, as all
+the frames potentially unwound through need to be proofed, which includes both
+system and application code -- and in essence proofing everything will make
+the system uninterruptible."
;; FIXME: a temporary compatibility workaround for CLX, if unsafe
;; unwinds are handled revisit it.