Readers calling CONDITION-WAIT don't interfere with each other.
CONDITION-WAIT used to set WAITQUEUE-DATA to *CURRENT-THREAD* causing
other readers entering FUTEX-WAIT to return with EWOULDBLOCK.
Set WAITQUEUE-DATA to NIL in readers, and to *CURRENT-THREAD* in
writers.
Also, fix a warning in :SEMAPHORE-MULTIPLE-WAITERS test.
(setf (mutex-%owner mutex) new-owner)
t)
#!-sb-lutex
- ;; This is a direct tranlation of the Mutex 2 algorithm from
+ ;; This is a direct translation of the Mutex 2 algorithm from
;; "Futexes are Tricky" by Ulrich Drepper.
(let ((old (sb!ext:compare-and-swap (mutex-state mutex)
+lock-free+
;; mutex on our way out.
(without-interrupts
(unwind-protect
- (let ((me *current-thread*))
+ (let ((me nil))
;; This setf becomes visible to other CPUS due to the
;; usual memory barrier semantics of lock
;; acquire/release.
(or to-usec 0))))
((1) (signal-deadline))
((2))
+ ;; EWOULDBLOCK, -1 here, is the possible spurious
+ ;; wakeup case. 0 is the normal wakeup.
(otherwise (return))))))
;; If we are interrupted while waiting, we should do these
;; things before returning. Ideally, in the case of an
(defun condition-notify (queue &optional (n 1))
#!+sb-doc
"Notify N threads waiting on QUEUE. The same mutex that is used in
-the correspoinding condition-wait must be held by this thread during
+the corresponding CONDITION-WAIT must be held by this thread during
this call."
#!-sb-thread (declare (ignore queue n))
#!-sb-thread (error "Not supported in unithread builds.")
| (mp:make-process #'roomy)))
|#
+(with-test (:name (:condition-variable :wait-multiple))
+ (loop repeat 40 do
+ (let ((waitqueue (sb-thread:make-waitqueue :name "Q"))
+ (mutex (sb-thread:make-mutex :name "M"))
+ (failedp nil))
+ (format t ".")
+ (finish-output t)
+ (let ((threads (loop repeat 200
+ collect
+ (sb-thread:make-thread
+ (lambda ()
+ (handler-case
+ (sb-sys:with-deadline (:seconds 0.01)
+ (sb-thread:with-mutex (mutex)
+ (sb-thread:condition-wait waitqueue
+ mutex)
+ (setq failedp t)))
+ (sb-sys:deadline-timeout (c)
+ (declare (ignore c)))))))))
+ (mapc #'sb-thread:join-thread threads)
+ (assert (not failedp))))))
+
(with-test (:name (:condition-variable :notify-multiple))
(flet ((tester (notify-fun)
(let ((queue (make-waitqueue :name "queue"))
(values
(loop for r from 0 below n
collect
- (let ((r r))
- (sb-thread:make-thread (lambda ()
- (let ((sem semaphore))
- (dotimes (s i)
- (sb-thread:wait-on-semaphore sem))))
- :name "reader")))
+ (sb-thread:make-thread
+ (lambda ()
+ (let ((sem semaphore))
+ (dotimes (s i)
+ (sb-thread:wait-on-semaphore sem))))
+ :name "reader"))
(* n i)))
(make-writers (n readers i)
(let ((j (* readers i)))
(let ((writers
(loop for w from 0 below n
collect
- (let ((w w))
- (sb-thread:make-thread (lambda ()
- (let ((sem semaphore))
- (dotimes (s k)
- (sb-thread:signal-semaphore sem))))
- :name "writer")))))
+ (sb-thread:make-thread
+ (lambda ()
+ (let ((sem semaphore))
+ (dotimes (s k)
+ (sb-thread:signal-semaphore sem))))
+ :name "writer"))))
(assert (zerop rem))
writers)
(+ rem (* n k))))))
;;; 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.26.3"
+"1.0.26.4"