From e94fe1bcf814af45ca9eeb4721df17c58afa4d76 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Sun, 29 Apr 2007 14:04:17 +0000 Subject: [PATCH] 1.0.5.2: non-racy WITH-SPINLOCK-AND-WITHOUT-GCING * 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 | 4 ++++ src/code/sysmacs.lisp | 12 +++++++----- src/code/target-hash-table.lisp | 22 +++++++--------------- version.lisp-expr | 2 +- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/NEWS b/NEWS index 9f504f5..ca11a2a 100644 --- 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 diff --git a/src/code/sysmacs.lisp b/src/code/sysmacs.lisp index 3556bc1..aca1cc5 100644 --- a/src/code/sysmacs.lisp +++ b/src/code/sysmacs.lisp @@ -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)))) ;;; EOF-OR-LOSE is a useful macro that handles EOF. diff --git a/src/code/target-hash-table.lisp b/src/code/target-hash-table.lisp index c25c730..2011304 100644 --- a/src/code/target-hash-table.lisp +++ b/src/code/target-hash-table.lisp @@ -14,30 +14,22 @@ ;;;; 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)) diff --git a/version.lisp-expr b/version.lisp-expr index dd972c5..3c1b629 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -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" -- 1.7.10.4