1.0.5.2: non-racy WITH-SPINLOCK-AND-WITHOUT-GCING
authorNikodemus Siivola <nikodemus@random-state.net>
Sun, 29 Apr 2007 14:04:17 +0000 (14:04 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Sun, 29 Apr 2007 14:04:17 +0000 (14:04 +0000)
 * It used to be possible for an interrupt or a GC request to come
   in during the small window after RECEIVE-PENDING-INTERRUPTS, but
   while we were running with interrupts and GC disabled. This would
   leave it pending and block further ones -- without any guarantee
   when the next one would come in.

   Experimentally this could also deadlock GC, but the code path
   leading to that is not entirely clear.

 * WITHOUT-GCING can be implemented by using just a single UWP, so do
   it like that.

NEWS
src/code/sysmacs.lisp
src/code/target-hash-table.lisp
version.lisp-expr

diff --git a/NEWS b/NEWS
index 9f504f5..ca11a2a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,8 @@
 ;;;; -*- coding: utf-8; -*-
+changes in sbcl-1.0.6 relative to sbcl-1.0.5:
+  * bug fix: GETHASH, (SETF GETHASH), CLRHASH and REMHASH are now
+    interrupt safe.
+
 changes in sbcl-1.0.5 relative to sbcl-1.0.4:
   * incompatible change: removed writer methods for host-ent-name,
     host-ent-addresses -- changing the values did not update the DNS
index 3556bc1..aca1cc5 100644 (file)
@@ -49,11 +49,13 @@ system will be deadlocked. Since SBCL does not currently document its internal
 locks, application code can never be certain that this invariant is
 maintained."
   `(unwind-protect
-        (without-interrupts
-          (let ((*gc-inhibit* t))
-            ,@body))
-     ;; the test is racy, but it can err only on the overeager side
-     (sb!kernel::maybe-handle-pending-gc)))
+        (let* ((*interrupts-enabled* nil)
+               (*gc-inhibit* t))
+          ,@body)
+     (when (or (and *interrupts-enabled* *interrupt-pending*)
+               (and (not *gc-inhibit*)
+                    (or *gc-pending* #!+sb-thread *stop-for-gc-pending*)))
+       (sb!unix::receive-pending-interrupt))))
 
 \f
 ;;; EOF-OR-LOSE is a useful macro that handles EOF.
index c25c730..2011304 100644 (file)
 \f
 ;;;; utilities
 
-;; This stuff is performance critical and unwind-protect is too
-;; slow. And without the locking the next vector can get cyclic
-;; causing looping in a WITHOUT-GCING form, SHRINK-VECTOR can corrupt
-;; memory and who knows what else.
+;;; Without the locking the next vector can get cyclic causing
+;;; looping in a WITHOUT-GCING form, SHRINK-VECTOR can corrupt memory
+;;; and who knows what else.
+;;;
+;;; WITHOUT-GCING implies WITHOUT-INTERRUPTS.
 (defmacro with-spinlock-and-without-gcing ((spinlock) &body body)
   #!-sb-thread
   (declare (ignore spinlock))
-  (with-unique-names (old-gc-inhibit old-interrupts-enabled)
-    `(let ((,old-gc-inhibit *gc-inhibit*)
-           (,old-interrupts-enabled *interrupts-enabled*)
-           (*interrupts-enabled* nil)
-           (*gc-inhibit* t))
+  `(without-gcing
        (unwind-protect
             (progn
               #!+sb-thread
               (sb!thread::get-spinlock ,spinlock)
               ,@body)
          #!+sb-thread
-         (sb!thread::release-spinlock ,spinlock)
-         (let ((*interrupts-enabled* ,old-interrupts-enabled)
-               (*gc-inhibit* ,old-gc-inhibit))
-           ;; the test is racy, but it can err only on the overeager
-           ;; side
-           (sb!kernel::maybe-handle-pending-gc))))))
+         (sb!thread::release-spinlock ,spinlock))))
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
   (defconstant max-hash sb!xc:most-positive-fixnum))
index dd972c5..3c1b629 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.5.1"
+"1.0.5.2"