X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fthreads.impure.lisp;h=20ac538d8c59d0f9a9b96c4a7d8860df6be30b3c;hb=b14aefb22fd710673b1a1005add3c0425713d2a0;hp=3dc340da1972527faf477b365019784e8793f905;hpb=66846b840130135ad644ce011f22bf3aaca9f3cf;p=sbcl.git diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index 3dc340d..20ac538 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -37,10 +37,6 @@ (with-mutex (mutex) mutex))) -(with-test (:name (:with-spinlock :basics)) - (let ((spinlock (make-spinlock))) - (with-spinlock (spinlock)))) - (sb-alien:define-alien-routine "check_deferrables_blocked_or_lose" void (where sb-alien:unsigned-long)) @@ -72,23 +68,23 @@ (throw 'xxx nil)))) (check-deferrables-unblocked-or-lose 0)) -#-sb-thread (sb-ext:quit :unix-status 104) +#-sb-thread (sb-ext:exit :code 104) ;;;; Now the real tests... -(with-test (:name (:interrupt-thread :deferrables-unblocked-by-spinlock)) - (let ((spinlock (sb-thread::make-spinlock)) +(with-test (:name (:interrupt-thread :deferrables-unblocked-by-lock)) + (let ((lock (sb-thread::make-mutex)) (thread (sb-thread:make-thread (lambda () (loop (sleep 1)))))) - (sb-thread::get-spinlock spinlock) + (sb-thread::grab-mutex lock) (sb-thread:interrupt-thread thread (lambda () (check-deferrables-blocked-or-lose 0) - (sb-thread::get-spinlock spinlock) + (sb-thread::grab-mutex lock) (check-deferrables-unblocked-or-lose 0) - (sb-ext:quit))) + (sb-thread:abort-thread))) (sleep 1) - (sb-thread::release-spinlock spinlock))) + (sb-thread::release-mutex lock))) ;;; compare-and-swap @@ -156,11 +152,11 @@ (with-test (:name (:join-thread :nlx :default)) (let ((sym (gensym))) - (assert (eq sym (join-thread (make-thread (lambda () (sb-ext:quit))) + (assert (eq sym (join-thread (make-thread (lambda () (sb-thread:abort-thread))) :default sym))))) (with-test (:name (:join-thread :nlx :error)) - (raises-error? (join-thread (make-thread (lambda () (sb-ext:quit)))) + (raises-error? (join-thread (make-thread (lambda () (sb-thread:abort-thread)))) join-thread-error)) (with-test (:name (:join-thread :multiple-values)) @@ -179,7 +175,7 @@ (sb-thread:make-thread (lambda () (with-mutex (mutex) (sb-thread:condition-wait queue mutex)) - (sb-ext:quit)))) + (sb-thread:abort-thread)))) (let ((start-time (get-internal-run-time))) (funcall function) (prog1 (- (get-internal-run-time) start-time) @@ -229,38 +225,11 @@ (assert (ours-p (mutex-value l)) nil "5")) (assert (eql (mutex-value l) nil) nil "6")))) -(with-test (:name (:with-recursive-spinlock :basics)) - (labels ((ours-p (value) - (eq *current-thread* value))) - (let ((l (make-spinlock :name "rec"))) - (assert (eql (spinlock-value l) nil) nil "1") - (with-recursive-spinlock (l) - (assert (ours-p (spinlock-value l)) nil "3") - (with-recursive-spinlock (l) - (assert (ours-p (spinlock-value l)) nil "4")) - (assert (ours-p (spinlock-value l)) nil "5")) - (assert (eql (spinlock-value l) nil) nil "6")))) - (with-test (:name (:mutex :nesting-mutex-and-recursive-lock)) (let ((l (make-mutex :name "a mutex"))) (with-mutex (l) (with-recursive-lock (l))))) -(with-test (:name (:spinlock :nesting-spinlock-and-recursive-spinlock)) - (let ((l (make-spinlock :name "a spinlock"))) - (with-spinlock (l) - (with-recursive-spinlock (l))))) - -(with-test (:name (:spinlock :more-basics)) - (let ((l (make-spinlock :name "spinlock"))) - (assert (eql (spinlock-value l) nil) ((spinlock-value l)) - "spinlock not free (1)") - (with-spinlock (l) - (assert (eql (spinlock-value l) *current-thread*) ((spinlock-value l)) - "spinlock not taken")) - (assert (eql (spinlock-value l) nil) ((spinlock-value l)) - "spinlock not free (2)"))) - ;; test that SLEEP actually sleeps for at least the given time, even ;; if interrupted by another thread exiting/a gc/anything (with-test (:name (:sleep :continue-sleeping-after-interrupt)) @@ -342,8 +311,6 @@ (grab-mutex m :waitp nil))))))))) (with-test (:name (:grab-mutex :timeout :acquisition-fail)) - #+sb-lutex - (error "Mutex timeout not supported here.") (let ((m (make-mutex)) (w (make-semaphore))) (with-mutex (m) @@ -358,8 +325,6 @@ (assert (null (join-thread th))))))) (with-test (:name (:grab-mutex :timeout :acquisition-success)) - #+sb-lutex - (error "Mutex timeout not supported here.") (let ((m (make-mutex)) (child)) (with-mutex (m) @@ -368,8 +333,6 @@ (assert (eq (join-thread child) 't)))) (with-test (:name (:grab-mutex :timeout+deadline)) - #+sb-lutex - (error "Mutex timeout not supported here.") (let ((m (make-mutex)) (w (make-semaphore))) (with-mutex (m) @@ -384,8 +347,6 @@ (assert (eq (join-thread th) :deadline)))))) (with-test (:name (:grab-mutex :waitp+deadline)) - #+sb-lutex - (error "Mutex timeout not supported here.") (let ((m (make-mutex))) (with-mutex (m) (assert (eq (join-thread @@ -526,7 +487,7 @@ (interrupt-thread child (lambda () (format t "child pid ~A~%" *current-thread*) - (when quit-p (sb-ext:quit)))) + (when quit-p (abort-thread)))) (sleep 1) child)) @@ -737,7 +698,7 @@ (sb-unix::strerror) reference-errno) (force-output) - (sb-ext:quit :unix-status 1))))))) + (abort-thread))))))) ;; (nanosleep -1 0) does not fail on FreeBSD (with-test (:name (:exercising-concurrent-syscalls)) @@ -764,13 +725,13 @@ (format t "~&errno test done~%") -(with-test (:name (:terminate-thread-restart)) +(with-test (:name :all-threads-have-abort-restart) (loop repeat 100 do (let ((thread (sb-thread:make-thread (lambda () (sleep 0.1))))) (sb-thread:interrupt-thread thread (lambda () - (assert (find-restart 'sb-thread:terminate-thread))))))) + (assert (find-restart 'abort))))))) (sb-ext:gc :full t) @@ -852,11 +813,12 @@ ;; now SOMETHING is gc'ed and the binding stack looks like this: 0, ;; 0, SOMETHING, 0 (because the symbol slots are zeroed on ;; unbinding but values are not). - (let ((*x* nil)) + (let ((*x* nil) + (binding-pointer-delta (ash 2 (- sb-vm:word-shift sb-vm:n-fixnum-tag-bits)))) ;; bump bsp as if a BIND had just started - (incf sb-vm::*binding-stack-pointer* 2) + (incf sb-vm::*binding-stack-pointer* binding-pointer-delta) (wait-for-gc) - (decf sb-vm::*binding-stack-pointer* 2)))) + (decf sb-vm::*binding-stack-pointer* binding-pointer-delta)))) (with-test (:name (:binding-stack-gc-safety)) (let (threads) @@ -1079,37 +1041,34 @@ ;;; Make sure that a deadline handler is not invoked twice in a row in ;;; CONDITION-WAIT. See LP #512914 for a detailed explanation. ;;; -#-sb-lutex ; See KLUDGE above: no deadlines for condition-wait+lutexes. (with-test (:name (:condition-wait :deadlines :LP-512914)) - (let ((n 2) ; was empirically enough to trigger the bug + (let ((n 2) ; was empirically enough to trigger the bug (mutex (sb-thread:make-mutex)) (waitq (sb-thread:make-waitqueue)) (threads nil) (deadline-handler-run-twice? nil)) (dotimes (i n) (let ((child - (sb-thread:make-thread - #'(lambda () - (handler-bind - ((sb-sys:deadline-timeout - (let ((already? nil)) - #'(lambda (c) - (when already? - (setq deadline-handler-run-twice? t)) - (setq already? t) - (sleep 0.2) - (sb-thread:condition-broadcast waitq) - (sb-sys:defer-deadline 10.0 c))))) - (sb-sys:with-deadline (:seconds 0.1) - (sb-thread:with-mutex (mutex) - (sb-thread:condition-wait waitq mutex)))))))) + (sb-thread:make-thread + #'(lambda () + (handler-bind + ((sb-sys:deadline-timeout + (let ((already? nil)) + #'(lambda (c) + (when already? + (setq deadline-handler-run-twice? t)) + (setq already? t) + (sleep 0.2) + (sb-thread:condition-broadcast waitq) + (sb-sys:defer-deadline 10.0 c))))) + (sb-sys:with-deadline (:seconds 0.1) + (sb-thread:with-mutex (mutex) + (sb-thread:condition-wait waitq mutex)))))))) (push child threads))) (mapc #'sb-thread:join-thread threads) (assert (not deadline-handler-run-twice?)))) (with-test (:name (:condition-wait :signal-deadline-with-interrupts-enabled)) - #+darwin - (error "Bad Darwin") (let ((mutex (sb-thread:make-mutex)) (waitq (sb-thread:make-waitqueue)) (A-holds? :unknown) @@ -1135,7 +1094,8 @@ (sb-sys:defer-deadline 10.0 c)))) (sb-sys:with-deadline (:seconds 0.1) (sb-thread:with-mutex (mutex) - (sb-thread:condition-wait waitq mutex))))))) + (sb-thread:condition-wait waitq mutex))))) + :name "A")) (setq B (sb-thread:make-thread #'(lambda () (thread-yield) @@ -1154,7 +1114,8 @@ (sb-sys:defer-deadline 10.0 c)))) (sb-sys:with-deadline (:seconds 0.1) (sb-thread:with-mutex (mutex) - (sb-thread:condition-wait waitq mutex))))))) + (sb-thread:condition-wait waitq mutex))))) + :name "B")) (sb-thread:join-thread A) (sb-thread:join-thread B) (let ((A-result (list A-holds? A-interrupts-enabled?)) @@ -1166,7 +1127,10 @@ ;; behaviour. (cond ((equal A-result '(t t)) (assert (equal B-result '(nil t)))) ((equal B-result '(t t)) (assert (equal A-result '(nil t)))) - (t (error "Failure: fall through.")))))) + (t + (error "Failure: fell through wit A: ~S, B: ~S" + A-result + B-result)))))) (with-test (:name (:mutex :finalization)) (let ((a nil)) @@ -1202,15 +1166,13 @@ (unless (zerop n) (setf ok nil) (format t "N != 0 (~A)~%" n) - (sb-ext:quit))))))))) + (abort-thread))))))))) (wait-for-threads threads) (assert ok))) (format t "infodb test done~%") -(with-test (:name (:backtrace)) - #+darwin - (error "Prone to crash on Darwin, cause unknown.") +(with-test (:name :backtrace) ;; Printing backtraces from several threads at once used to hang the ;; whole SBCL process (discovered by accident due to a timer.impure ;; test misbehaving). The cause was that packages weren't even @@ -1229,9 +1191,7 @@ (format t "~&starting gc deadlock test: WARNING: THIS TEST WILL HANG ON FAILURE!~%") -(with-test (:name (:gc-deadlock)) - #+darwin - (error "Prone to hang on Darwin due to interrupt issues.") +(with-test (:name :gc-deadlock) ;; Prior to 0.9.16.46 thread exit potentially deadlocked the ;; GC due to *all-threads-lock* and session lock. On earlier ;; versions and at least on one specific box this test is good enough @@ -1395,32 +1355,36 @@ (with-test (:name (:deadlock-detection :interrupts)) (let* ((m1 (sb-thread:make-mutex :name "M1")) (m2 (sb-thread:make-mutex :name "M2")) + (t1-can-go (sb-thread:make-semaphore :name "T1 can go")) + (t2-can-go (sb-thread:make-semaphore :name "T2 can go")) (t1 (sb-thread:make-thread (lambda () (sb-thread:with-mutex (m1) - (sleep 0.3) - :ok)) + (sb-thread:wait-on-semaphore t1-can-go) + :ok1)) :name "T1")) (t2 (sb-thread:make-thread (lambda () - (sleep 0.1) + (sb-ext:wait-for (eq t1 (sb-thread:mutex-owner m1))) (sb-thread:with-mutex (m1 :wait-p t) - (sleep 0.2) - :ok)) + (sb-thread:wait-on-semaphore t2-can-go) + :ok2)) :name "T2"))) - (sleep 0.2) + (sb-ext:wait-for (eq m1 (sb-thread::thread-waiting-for t2))) (sb-thread:interrupt-thread t2 (lambda () (sb-thread:with-mutex (m2 :wait-p t) - (sleep 0.3)))) - (sleep 0.05) + (sb-ext:wait-for + (eq m2 (sb-thread::thread-waiting-for t1))) + (sb-thread:signal-semaphore t2-can-go)))) + (sb-ext:wait-for (eq t2 (sb-thread:mutex-owner m2))) (sb-thread:interrupt-thread t1 (lambda () (sb-thread:with-mutex (m2 :wait-p t) - (sleep 0.3)))) + (sb-thread:signal-semaphore t1-can-go)))) ;; both threads should finish without a deadlock or deadlock ;; detection error (let ((res (list (sb-thread:join-thread t1) (sb-thread:join-thread t2)))) - (assert (equal '(:ok :ok) res))))) + (assert (equal '(:ok1 :ok2) res))))) (with-test (:name (:deadlock-detection :gc)) ;; To semi-reliably trigger the error (in SBCL's where) @@ -1443,3 +1407,26 @@ (let ((res (list (sb-thread:join-thread t1) (sb-thread:join-thread t2)))) (assert (equal '(:ok :ok) res))))) + +(with-test (:name :spinlock-api) + (let* ((warned 0) + (funs + (handler-bind ((sb-int:early-deprecation-warning (lambda (_) + (declare (ignore _)) + (incf warned)))) + (list (compile nil `(lambda (lock) + (sb-thread::with-spinlock (lock) + t))) + (compile nil `(lambda () + (sb-thread::make-spinlock :name "foo"))) + (compile nil `(lambda (lock) + (sb-thread::get-spinlock lock))) + (compile nil `(lambda (lock) + (sb-thread::release-spinlock lock))))))) + (assert (eql 4 warned)) + (handler-bind ((warning #'error)) + (destructuring-bind (with make get release) funs + (let ((lock (funcall make))) + (funcall get lock) + (funcall release lock) + (assert (eq t (funcall with lock))))))))