(with-test (:name atomic-update
:skipped-on '(not :sb-thread))
- (let ((x (cons :count 0)))
+ (let ((x (cons :count 0))
+ (nthreads (ecase sb-vm:n-word-bits (32 100) (64 1000))))
(mapc #'sb-thread:join-thread
- (loop repeat 1000
+ (loop repeat nthreads
collect (sb-thread:make-thread
(lambda ()
(loop repeat 1000
do (atomic-update (cdr x) #'1+)
(sleep 0.00001))))))
- (assert (equal x '(:count . 1000000)))))
+ (assert (equal x `(:count ,@(* 1000 nthreads))))))
(with-test (:name mutex-owner)
;; Make sure basics are sane on unithreaded ports as well
(let ((mutex (make-mutex)))
- (get-mutex mutex)
+ (grab-mutex mutex)
(assert (eq *current-thread* (mutex-value mutex)))
(handler-bind ((warning #'error))
(release-mutex mutex))
;;; Condition-wait should not be interruptible under WITHOUT-INTERRUPTS
-(with-test (:name without-interrupts+condition-wait
- :skipped-on '(not :sb-thread))
+(with-test (:name :without-interrupts+condition-wait
+ :skipped-on '(not :sb-thread)
+ :fails-on '(and :win32 :sb-futex))
(let* ((lock (make-mutex))
(queue (make-waitqueue))
(thread (make-thread (lambda ()
(sleep 1)
(assert (not (thread-alive-p thread)))))
-;;; GET-MUTEX should not be interruptible under WITHOUT-INTERRUPTS
+;;; GRAB-MUTEX should not be interruptible under WITHOUT-INTERRUPTS
-(with-test (:name without-interrupts+get-mutex :skipped-on '(not :sb-thread))
+(with-test (:name :without-interrupts+grab-mutex :skipped-on '(not :sb-thread))
(let* ((lock (make-mutex))
- (bar (progn (get-mutex lock) nil))
+ (bar (progn (grab-mutex lock) nil))
(thread (make-thread (lambda ()
(sb-sys:without-interrupts
(with-mutex (lock)
(assert (eq :aborted (join-thread thread :default :aborted)))
(assert bar)))
-(with-test (:name parallel-find-class :skipped-on '(not :sb-thread))
+(with-test (:name :parallel-find-class :skipped-on '(not :sb-thread))
(let* ((oops nil)
(threads (loop repeat 10
collect (make-thread (lambda ()
;;;; SYMBOL-VALUE-IN-THREAD
-(with-test (:name symbol-value-in-thread.1)
+(with-test (:name :symbol-value-in-thread.1)
(let ((* (cons t t)))
(assert (eq * (symbol-value-in-thread '* *current-thread*)))
(setf (symbol-value-in-thread '* *current-thread*) 123)
(assert (= 123 (symbol-value-in-thread '* *current-thread*)))
(assert (= 123 *))))
-(with-test (:name symbol-value-in-thread.2 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.2 :skipped-on '(not :sb-thread))
(let* ((parent *current-thread*)
(semaphore (make-semaphore))
(child (make-thread (lambda ()
;;; Disabled on Darwin due to deadlocks caused by apparent OS specific deadlocks,
;;; wich _appear_ to be caused by malloc() and free() not being thread safe: an
;;; interrupted malloc in one thread can apparently block a free in another.
-(with-test (:name symbol-value-in-thread.3
+(with-test (:name :symbol-value-in-thread.3
:skipped-on '(not :sb-thread))
(let* ((parent *current-thread*)
(semaphore (make-semaphore))
(loop repeat (random 128)
do (setf ** *)))))))
(write-string "; ")
- (dotimes (i 15000)
+ (dotimes (i #+win32 2000 #-win32 15000)
(when (zerop (mod i 200))
(write-char #\.)
(force-output))
(setf running nil)
(join-thread noise)))
-(with-test (:name symbol-value-in-thread.4 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.4 :skipped-on '(not :sb-thread))
(let* ((parent *current-thread*)
(semaphore (make-semaphore))
(child (make-thread (lambda ()
(signal-semaphore semaphore)
(assert (equal '(nil nil) (multiple-value-list (join-thread child))))))
-(with-test (:name symbol-value-in-thread.5 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.5 :skipped-on '(not :sb-thread))
(let* ((parent *current-thread*)
(semaphore (make-semaphore))
(child (make-thread (lambda ()
(assert (equal (list *current-thread* 'this-is-new (list :read :unbound-in-thread))
(join-thread child)))))
-(with-test (:name symbol-value-in-thread.6 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.6 :skipped-on '(not :sb-thread))
(let* ((parent *current-thread*)
(semaphore (make-semaphore))
(name (gensym))
(unless (equal res want)
(error "wanted ~S, got ~S" want res)))))
-(with-test (:name symbol-value-in-thread.7 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.7 :skipped-on '(not :sb-thread))
(let ((child (make-thread (lambda ())))
(error-occurred nil))
(join-thread child)
(sb-thread::symbol-value-in-thread-error-info e)))))
(assert error-occurred)))
-(with-test (:name symbol-value-in-thread.8 :skipped-on '(not :sb-thread))
+(with-test (:name :symbol-value-in-thread.8 :skipped-on '(not :sb-thread))
(let ((child (make-thread (lambda ())))
(error-occurred nil))
(join-thread child)
(sb-thread::symbol-value-in-thread-error-info e)))))
(assert error-occurred)))
-(with-test (:name deadlock-detection.1 :skipped-on '(not :sb-thread))
+(with-test (:name :deadlock-detection.1 :skipped-on '(not :sb-thread))
(loop
repeat 1000
do (flet ((test (ma mb sa sb)
(assert (or (equal '(:deadlock :ok) res)
(equal '(:ok :deadlock) res))))))))
-(with-test (:name deadlock-detection.2 :skipped-on '(not :sb-thread))
+(with-test (:name :deadlock-detection.2 :skipped-on '(not :sb-thread))
(let* ((m1 (sb-thread:make-mutex :name "M1"))
(m2 (sb-thread:make-mutex :name "M2"))
(s1 (sb-thread:make-semaphore :name "S1"))
(assert (stringp err)))
(assert (eq :ok (sb-thread:join-thread t1)))))
-(with-test (:name deadlock-detection.3 :skipped-on '(not :sb-thread))
+(with-test (:name :deadlock-detection.3 :skipped-on '(not :sb-thread))
(let* ((m1 (sb-thread:make-mutex :name "M1"))
(m2 (sb-thread:make-mutex :name "M2"))
(s1 (sb-thread:make-semaphore :name "S1"))
(assert (and (null value)
error))))
-(with-test (:name (:wait-for :basics) :fails-on :win32)
+(with-test (:name (:wait-for :basics))
(assert (not (sb-ext:wait-for nil :timeout 0.1)))
(assert (eql 42 (sb-ext:wait-for 42)))
(let ((n 0))
(assert (eql 100 (sb-ext:wait-for (when (= 100 (incf n))
n))))))
-(with-test (:name (:wait-for :deadline) :fails-on :win32)
+(with-test (:name (:wait-for :deadline))
(assert (eq :ok
(sb-sys:with-deadline (:seconds 10)
(assert (not (sb-ext:wait-for nil :timeout 0.1)))
(error "oops"))
(sb-sys:deadline-timeout () :deadline)))))
-(with-test (:name (:condition-wait :timeout :one-thread) :fails-on :win32)
+(with-test (:name (:condition-wait :timeout :one-thread))
(let ((mutex (make-mutex))
(waitqueue (make-waitqueue)))
(assert (not (with-mutex (mutex)
(unless (eql 50 ok)
(error "Wanted 50, got ~S" ok)))))
-(with-test (:name (:wait-on-semaphore :timeout :one-thread) :fails-on :win32)
+(with-test (:name (:wait-on-semaphore :timeout :one-thread))
(let ((sem (make-semaphore))
(n 0))
(signal-semaphore sem 10)
:skipped-on '(not :sb-thread))
(assert (eq :error
(handler-case
- (join-thread (make-thread (lambda () (sleep 10))) :timeout 0.01)
+ (join-thread (make-join-thread (lambda () (sleep 10))) :timeout 0.01)
(join-thread-error ()
:error))))
(let ((cookie (cons t t)))
(assert (eq cookie
- (join-thread (make-thread (lambda () (sleep 10)))
+ (join-thread (make-join-thread (lambda () (sleep 10)))
:timeout 0.01
:default cookie)))))
#+sb-thread
(sb-thread::block-deferrable-signals))))))
(let* ((threads (loop for i from 1 upto 100
- collect (make-thread #'critical :name (format nil "T~A" i))))
+ collect (make-join-thread #'critical :name (format nil "T~A" i))))
(safe nil)
(unsafe nil)
(interruptor (make-thread (lambda ()
(thread-error ()
:oops)))))
+;; SB-THREAD:MAKE-THREAD used to lock SB-THREAD:*MAKE-THREAD-LOCK*
+;; before entering WITHOUT-INTERRUPTS. When a thread which was
+;; executing SB-THREAD:MAKE-THREAD was interrupted with code which
+;; also called SB-THREAD:MAKE-THREAD, it could happen that the first
+;; thread already owned SB-THREAD:*MAKE-THREAD-LOCK* and the
+;; interrupting code thus made a recursive lock attempt.
+;;
+;; See (:TIMER :DISPATCH-THREAD :MAKE-THREAD :BUG-1180102) in
+;; timer.impure.lisp.
+(with-test (:name (make-thread :interrupt-with make-thread :bug-1180102)
+ :skipped-on '(not :sb-thread))
+ (dotimes (i 100)
+ (let ((threads '())
+ (parent *current-thread*))
+ (dotimes (i 100)
+ (push (make-thread
+ (lambda ()
+ (interrupt-thread
+ parent
+ (lambda () (push (make-thread (lambda ())) threads)))))
+ threads)
+ (push (make-thread (lambda ())) threads))
+ (mapc #'join-thread threads))))