Try to make test :deferrables-unblocked-by-lock more robust
[sbcl.git] / tests / threads.impure.lisp
1 ;;;; miscellaneous tests of thread stuff
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
8 ;;;; from CMU CL.
9 ;;;
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absoluely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
13
14 ; WHITE-BOX TESTS
15
16 (in-package "SB-THREAD")
17 (use-package :test-util)
18 (use-package "ASSERTOID")
19
20 (setf sb-unix::*on-dangerous-wait* :error)
21
22 (defun wait-for-threads (threads)
23   (mapc (lambda (thread) (sb-thread:join-thread thread :default nil)) threads)
24   (assert (not (some #'sb-thread:thread-alive-p threads))))
25
26 (with-test (:name (:threads :trivia))
27   (assert (eql 1 (length (list-all-threads))))
28
29   (assert (eq *current-thread*
30               (find (thread-name *current-thread*) (list-all-threads)
31                     :key #'thread-name :test #'equal)))
32
33   (assert (thread-alive-p *current-thread*)))
34
35 (with-test (:name (:with-mutex :basics))
36   (let ((mutex (make-mutex)))
37     (with-mutex (mutex)
38       mutex)))
39
40 (with-test (:name (:with-mutex :timeout))
41   (let ((m (make-mutex)))
42     (with-mutex (m)
43       (assert (null (join-thread (make-thread
44                                   (lambda ()
45                                     (with-mutex (m :timeout 0.1)
46                                       t)))))))
47     (assert (join-thread (make-thread
48                           (lambda ()
49                             (with-mutex (m :timeout 0.1)
50                               t)))))))
51
52 (sb-alien:define-alien-routine "check_deferrables_blocked_or_lose"
53     void
54   (where sb-alien:unsigned-long))
55 (sb-alien:define-alien-routine "check_deferrables_unblocked_or_lose"
56     void
57   (where sb-alien:unsigned-long))
58
59 (with-test (:name (:interrupt-thread :basics :no-unwinding))
60   (let ((a 0))
61     (interrupt-thread *current-thread* (lambda () (setq a 1)))
62     (assert (eql a 1))))
63
64 (with-test (:name (:interrupt-thread :deferrables-blocked))
65   (sb-thread:interrupt-thread sb-thread:*current-thread*
66                               (lambda ()
67                                 (check-deferrables-blocked-or-lose 0))))
68
69 (with-test (:name (:interrupt-thread :deferrables-unblocked))
70   (sb-thread:interrupt-thread sb-thread:*current-thread*
71                               (lambda ()
72                                 (with-interrupts
73                                   (check-deferrables-unblocked-or-lose 0)))))
74
75 (with-test (:name (:interrupt-thread :nlx))
76   (catch 'xxx
77     (sb-thread:interrupt-thread sb-thread:*current-thread*
78                                 (lambda ()
79                                   (check-deferrables-blocked-or-lose 0)
80                                   (throw 'xxx nil))))
81   (check-deferrables-unblocked-or-lose 0))
82
83 #-sb-thread (sb-ext:exit :code 104)
84
85 ;;;; Now the real tests...
86
87 (with-test (:name (:interrupt-thread :deferrables-unblocked-by-lock))
88   (let ((lock (sb-thread::make-mutex))
89         (thread (make-join-thread (lambda ()
90                                     (loop (sleep 1))))))
91     (sb-thread::grab-mutex lock)
92     (sb-thread:interrupt-thread thread
93                                 (lambda ()
94                                   (check-deferrables-blocked-or-lose 0)
95                                   (sb-thread::grab-mutex lock)
96                                   (check-deferrables-unblocked-or-lose 0)
97                                   (sb-thread:abort-thread)))
98     (sleep 3)
99     (sb-thread::release-mutex lock)))
100
101 ;;; compare-and-swap
102
103 (defmacro defincf (name accessor &rest args)
104   `(defun ,name (x)
105      (let* ((old (,accessor x ,@args))
106          (new (1+ old)))
107     (loop until (eq old (sb-ext:compare-and-swap (,accessor x ,@args) old new))
108        do (setf old (,accessor x ,@args)
109                 new (1+ old)))
110     new)))
111
112 (defstruct cas-struct (slot 0))
113
114 (defincf incf-car car)
115 (defincf incf-cdr cdr)
116 (defincf incf-slot cas-struct-slot)
117 (defincf incf-symbol-value symbol-value)
118 (defincf incf-svref/1 svref 1)
119 (defincf incf-svref/0 svref 0)
120
121 (defmacro def-test-cas (name init incf op)
122   `(with-test (:name ,name)
123      (flet ((,name (n)
124               (declare (fixnum n))
125               (let* ((x ,init)
126                      (run nil)
127                      (threads
128                       (loop repeat 10
129                             collect (sb-thread:make-thread
130                                      (lambda ()
131                                        (loop until run
132                                              do (sb-thread:thread-yield))
133                                        (loop repeat n do (,incf x)))))))
134                 (setf run t)
135                 (dolist (th threads)
136                   (sb-thread:join-thread th))
137                 (assert (= (,op x) (* 10 n))))))
138        (,name 200000))))
139
140 (def-test-cas test-cas-car (cons 0 nil) incf-car car)
141 (def-test-cas test-cas-cdr (cons nil 0) incf-cdr cdr)
142 (def-test-cas test-cas-slot (make-cas-struct) incf-slot cas-struct-slot)
143 (def-test-cas test-cas-value (let ((x '.x.))
144                                (set x 0)
145                                x)
146   incf-symbol-value symbol-value)
147 (def-test-cas test-cas-svref/0 (vector 0 nil) incf-svref/0 (lambda (x)
148                                                              (svref x 0)))
149 (def-test-cas test-cas-svref/1 (vector nil 0) incf-svref/1 (lambda (x)
150                                                              (svref x 1)))
151 (format t "~&compare-and-swap tests done~%")
152
153 (with-test (:name (:threads :more-trivia)))
154 (let ((old-threads (list-all-threads))
155       (thread (make-thread (lambda ()
156                              (assert (find *current-thread* *all-threads*))
157                              (sleep 2))))
158       (new-threads (list-all-threads)))
159   (assert (thread-alive-p thread))
160   (assert (eq thread (first new-threads)))
161   (assert (= (1+ (length old-threads)) (length new-threads)))
162   (sleep 3)
163   (assert (not (thread-alive-p thread))))
164
165 (with-test (:name (:join-thread :nlx :default))
166   (let ((sym (gensym)))
167     (assert (eq sym (join-thread (make-thread (lambda () (sb-thread:abort-thread)))
168                                  :default sym)))))
169
170 (with-test (:name (:join-thread :nlx :error))
171   (raises-error? (join-thread (make-thread (lambda () (sb-thread:abort-thread))))
172                  join-thread-error))
173
174 (with-test (:name (:join-thread :multiple-values))
175   (assert (equal '(1 2 3)
176                  (multiple-value-list
177                   (join-thread (make-thread (lambda () (values 1 2 3))))))))
178
179 ;;; We had appalling scaling properties for a while.  Make sure they
180 ;;; don't reappear.
181 (defun scaling-test (function &optional (nthreads 5))
182   "Execute FUNCTION with NTHREADS lurking to slow it down."
183   (let ((queue (sb-thread:make-waitqueue))
184         (mutex (sb-thread:make-mutex)))
185     ;; Start NTHREADS idle threads.
186     (dotimes (i nthreads)
187       (make-join-thread (lambda ()
188                           (with-mutex (mutex)
189                             (sb-thread:condition-wait queue mutex))
190                           (sb-thread:abort-thread))))
191     (let ((start-time (get-internal-run-time)))
192       (funcall function)
193       (prog1 (- (get-internal-run-time) start-time)
194         (sb-thread:condition-broadcast queue)))))
195 (defun fact (n)
196   "A function that does work with the CPU."
197   (if (zerop n) 1 (* n (fact (1- n)))))
198 (let ((work (lambda () (fact 15000))))
199   (let ((zero (scaling-test work 0))
200         (four (scaling-test work 4)))
201     ;; a slightly weak assertion, but good enough for starters.
202     (assert (< four (* 1.5 zero)))))
203
204 ;;; For one of the interupt-thread tests, we want a foreign function
205 ;;; that does not make syscalls
206
207 (with-open-file (o "threads-foreign.c" :direction :output :if-exists :supersede)
208   (format o "void loop_forever() { while(1) ; }~%"))
209 (sb-ext:run-program "/bin/sh"
210                     '("run-compiler.sh" "-sbcl-pic" "-sbcl-shared"
211                       "-o" "threads-foreign.so" "threads-foreign.c")
212                     :environment (test-util::test-env))
213 (sb-alien:load-shared-object (truename "threads-foreign.so"))
214 (sb-alien:define-alien-routine loop-forever sb-alien:void)
215 (delete-file "threads-foreign.c")
216
217
218 ;;; elementary "can we get a lock and release it again"
219 (with-test (:name (:mutex :basics))
220   (let ((l (make-mutex :name "foo"))
221         (p *current-thread*))
222     (assert (eql (mutex-value l) nil) nil "1")
223     (sb-thread:grab-mutex l)
224     (assert (eql (mutex-value l) p) nil "3")
225     (sb-thread:release-mutex l)
226     (assert (eql (mutex-value l) nil) nil "5")))
227
228 (with-test (:name (:with-recursive-lock :basics))
229   (labels ((ours-p (value)
230              (eq *current-thread* value)))
231     (let ((l (make-mutex :name "rec")))
232       (assert (eql (mutex-value l) nil) nil "1")
233       (sb-thread:with-recursive-lock (l)
234         (assert (ours-p (mutex-value l)) nil "3")
235         (sb-thread:with-recursive-lock (l)
236           (assert (ours-p (mutex-value l)) nil "4"))
237         (assert (ours-p (mutex-value l)) nil "5"))
238       (assert (eql (mutex-value l) nil) nil "6"))))
239
240 (with-test (:name (:with-recursive-lock :wait-p))
241   (let ((m (make-mutex)))
242     (with-mutex (m)
243       (assert (null (join-thread (make-thread
244                                   (lambda ()
245                                     (with-recursive-lock (m :wait-p nil)
246                                       t)))))))
247     (assert (join-thread (make-thread
248                           (lambda ()
249                             (with-recursive-lock (m :wait-p nil)
250                               t)))))))
251
252 (with-test (:name (:with-recursive-lock :wait-p :recursive))
253   (let ((m (make-mutex)))
254     (assert (join-thread (make-thread
255                           (lambda ()
256                             (with-recursive-lock (m :wait-p nil)
257                               (with-recursive-lock (m :wait-p nil)
258                                 t))))))))
259
260 (with-test (:name (:with-recursive-lock :timeout))
261   (let ((m (make-mutex)))
262     (with-mutex (m)
263       (assert (null (join-thread (make-thread
264                                   (lambda ()
265                                     (with-recursive-lock (m :timeout 0.1)
266                                       t)))))))
267     (assert (join-thread (make-thread
268                           (lambda ()
269                             (with-recursive-lock (m :timeout 0.1)
270                               t)))))))
271
272 (with-test (:name (:with-recursive-lock :timeout :recursive))
273   (let ((m (make-mutex)))
274     (assert (join-thread (make-thread
275                           (lambda ()
276                             (with-recursive-lock (m :timeout 0.1)
277                               (with-recursive-lock (m :timeout 0.1)
278                                 t))))))))
279
280 (with-test (:name (:mutex :nesting-mutex-and-recursive-lock))
281   (let ((l (make-mutex :name "a mutex")))
282     (with-mutex (l)
283       (with-recursive-lock (l)))))
284
285 ;; test that SLEEP actually sleeps for at least the given time, even
286 ;; if interrupted by another thread exiting/a gc/anything
287 (with-test (:name (:sleep :continue-sleeping-after-interrupt))
288   (let ((start-time (get-universal-time)))
289     (make-join-thread (lambda () (sleep 1) (sb-ext:gc :full t)))
290     (sleep 5)
291     (assert (>= (get-universal-time) (+ 5 start-time)))))
292
293
294 (with-test (:name (:condition-wait :basics-1))
295   (let ((queue (make-waitqueue :name "queue"))
296         (lock (make-mutex :name "lock"))
297         (n 0))
298     (labels ((in-new-thread ()
299                (with-mutex (lock)
300                  (assert (eql (mutex-value lock) *current-thread*))
301                  (format t "~A got mutex~%" *current-thread*)
302                  ;; now drop it and sleep
303                  (condition-wait queue lock)
304                  ;; after waking we should have the lock again
305                  (assert (eql (mutex-value lock) *current-thread*))
306                  (assert (eql n 1))
307                  (decf n))))
308       (make-join-thread #'in-new-thread)
309       (sleep 2)            ; give it  a chance to start
310       ;; check the lock is free while it's asleep
311       (format t "parent thread ~A~%" *current-thread*)
312       (assert (eql (mutex-value lock) nil))
313       (with-mutex (lock)
314         (incf n)
315         (condition-notify queue))
316       (sleep 1))))
317
318 (with-test (:name (:condition-wait :basics-2))
319   (let ((queue (make-waitqueue :name "queue"))
320         (lock (make-mutex :name "lock")))
321     (labels ((ours-p (value)
322                (eq *current-thread* value))
323              (in-new-thread ()
324                (with-recursive-lock (lock)
325                  (assert (ours-p (mutex-value lock)))
326                  (format t "~A got mutex~%" (mutex-value lock))
327                  ;; now drop it and sleep
328                  (condition-wait queue lock)
329                  ;; after waking we should have the lock again
330                  (format t "woken, ~A got mutex~%" (mutex-value lock))
331                  (assert (ours-p (mutex-value lock))))))
332       (make-join-thread #'in-new-thread)
333       (sleep 2)            ; give it  a chance to start
334       ;; check the lock is free while it's asleep
335       (format t "parent thread ~A~%" *current-thread*)
336       (assert (eql (mutex-value lock) nil))
337       (with-recursive-lock (lock)
338         (condition-notify queue))
339       (sleep 1))))
340
341 (with-test (:name (:mutex :contention))
342   (let ((mutex (make-mutex :name "contended")))
343     (labels ((run ()
344                (let ((me *current-thread*))
345                  (dotimes (i 100)
346                    (with-mutex (mutex)
347                      (sleep .03)
348                      (assert (eql (mutex-value mutex) me)))
349                    (assert (not (eql (mutex-value mutex) me))))
350                  (format t "done ~A~%" *current-thread*))))
351       (let ((kid1 (make-thread #'run))
352             (kid2 (make-thread #'run)))
353         (format t "contention ~A ~A~%" kid1 kid2)
354         (wait-for-threads (list kid1 kid2))))))
355
356 ;;; GRAB-MUTEX
357
358 (with-test (:name (:grab-mutex :waitp nil))
359   (let ((m (make-mutex)))
360     (with-mutex (m)
361       (assert (null (join-thread (make-thread
362                                   #'(lambda ()
363                                       (grab-mutex m :waitp nil)))))))))
364
365 (with-test (:name (:grab-mutex :timeout :acquisition-fail))
366   (let ((m (make-mutex))
367         (w (make-semaphore)))
368     (with-mutex (m)
369       (let ((th (make-thread
370                  #'(lambda ()
371                      (prog1
372                          (grab-mutex m :timeout 0.1)
373                        (signal-semaphore w))))))
374         ;; Wait for it to -- otherwise the detect the deadlock chain
375         ;; from JOIN-THREAD.
376         (wait-on-semaphore w)
377         (assert (null (join-thread th)))))))
378
379 (with-test (:name (:grab-mutex :timeout :acquisition-success))
380   (let ((m (make-mutex))
381         (child))
382     (with-mutex (m)
383       (setq child (make-thread #'(lambda () (grab-mutex m :timeout 1.0))))
384       (sleep 0.2))
385     (assert (eq (join-thread child) 't))))
386
387 (with-test (:name (:grab-mutex :timeout+deadline))
388   (let ((m (make-mutex))
389         (w (make-semaphore)))
390     (with-mutex (m)
391       (let ((th (make-thread #'(lambda ()
392                                  (sb-sys:with-deadline (:seconds 0.0)
393                                    (handler-case
394                                        (grab-mutex m :timeout 0.0)
395                                      (sb-sys:deadline-timeout ()
396                                        (signal-semaphore w)
397                                        :deadline)))))))
398         (wait-on-semaphore w)
399         (assert (eq (join-thread th) :deadline))))))
400
401 (with-test (:name (:grab-mutex :waitp+deadline))
402   (let ((m (make-mutex)))
403     (with-mutex (m)
404       (assert (eq (join-thread
405                    (make-thread #'(lambda ()
406                                     (sb-sys:with-deadline (:seconds 0.0)
407                                       (handler-case
408                                           (grab-mutex m :waitp nil)
409                                         (sb-sys:deadline-timeout ()
410                                           :deadline))))))
411                   'nil)))))
412
413 ;;; semaphores
414
415 (defmacro raises-timeout-p (&body body)
416   `(handler-case (progn (progn ,@body) nil)
417     (sb-ext:timeout () t)))
418
419 (with-test (:name (:semaphore :wait-forever))
420   (let ((sem (make-semaphore :count 0)))
421     (assert (raises-timeout-p
422               (sb-ext:with-timeout 0.1
423                 (wait-on-semaphore sem))))))
424
425 (with-test (:name (:semaphore :initial-count))
426   (let ((sem (make-semaphore :count 1)))
427     (sb-ext:with-timeout 0.1
428       (wait-on-semaphore sem))))
429
430 (with-test (:name (:semaphore :wait-then-signal))
431   (let ((sem (make-semaphore))
432         (signalled-p nil))
433     (make-join-thread (lambda ()
434                         (sleep 0.1)
435                         (setq signalled-p t)
436                         (signal-semaphore sem)))
437     (wait-on-semaphore sem)
438     (assert signalled-p)))
439
440 (with-test (:name (:semaphore :signal-then-wait))
441   (let ((sem (make-semaphore))
442         (signalled-p nil))
443     (make-join-thread (lambda ()
444                         (signal-semaphore sem)
445                         (setq signalled-p t)))
446     (loop until signalled-p)
447     (wait-on-semaphore sem)
448     (assert signalled-p)))
449
450 (defun test-semaphore-multiple-signals (wait-on-semaphore)
451   (let* ((sem (make-semaphore :count 5))
452          (threads (loop repeat 20 collecting
453                         (make-join-thread (lambda ()
454                                             (funcall wait-on-semaphore sem))))))
455     (flet ((count-live-threads ()
456              (count-if #'thread-alive-p threads)))
457       (sleep 0.5)
458       (assert (= 15 (count-live-threads)))
459       (signal-semaphore sem 10)
460       (sleep 0.5)
461       (assert (= 5 (count-live-threads)))
462       (signal-semaphore sem 3)
463       (sleep 0.5)
464       (assert (= 2 (count-live-threads)))
465       (signal-semaphore sem 4)
466       (sleep 0.5)
467       (assert (= 0 (count-live-threads))))))
468
469 (with-test (:name (:semaphore :multiple-signals))
470   (test-semaphore-multiple-signals #'wait-on-semaphore))
471
472 (with-test (:name (:try-semaphore :trivial-fail))
473   (assert (eq (try-semaphore (make-semaphore :count 0)) 'nil)))
474
475 (with-test (:name (:try-semaphore :trivial-success))
476   (let ((sem (make-semaphore :count 1)))
477     (assert (try-semaphore sem))
478     (assert (zerop (semaphore-count sem)))))
479
480 (with-test (:name (:try-semaphore :trivial-fail :n>1))
481   (assert (eq (try-semaphore (make-semaphore :count 1) 2) 'nil)))
482
483 (with-test (:name (:try-semaphore :trivial-success :n>1))
484   (let ((sem (make-semaphore :count 10)))
485     (assert (try-semaphore sem 5))
486     (assert (try-semaphore sem 5))
487     (assert (zerop (semaphore-count sem)))))
488
489 (with-test (:name (:try-semaphore :emulate-wait-on-semaphore))
490   (flet ((busy-wait-on-semaphore (sem)
491            (loop until (try-semaphore sem) do (sleep 0.001))))
492     (test-semaphore-multiple-signals #'busy-wait-on-semaphore)))
493
494 ;;; Here we test that interrupting TRY-SEMAPHORE does not leave a
495 ;;; semaphore in a bad state.
496 (with-test (:name (:try-semaphore :interrupt-safe))
497   (flet ((make-threads (count fn)
498            (loop repeat count collect (make-thread fn)))
499          (kill-thread (thread)
500            (when (thread-alive-p thread)
501              (ignore-errors (terminate-thread thread))))
502          (count-live-threads (threads)
503            (count-if #'thread-alive-p threads)))
504     ;; WAITERS will already be waiting on the semaphore while
505     ;; threads-being-interrupted will perform TRY-SEMAPHORE on that
506     ;; semaphore, and MORE-WAITERS are new threads trying to wait on
507     ;; the semaphore during the interruption-fire.
508     (let* ((sem (make-semaphore :count 100))
509            (waiters (make-threads 20 #'(lambda ()
510                                          (wait-on-semaphore sem))))
511            (triers  (make-threads 40 #'(lambda ()
512                                          (sleep (random 0.01))
513                                          (try-semaphore sem (1+ (random 5))))))
514            (more-waiters
515             (loop repeat 10
516                   do (kill-thread (nth (random 40) triers))
517                   collect (make-thread #'(lambda () (wait-on-semaphore sem)))
518                   do (kill-thread (nth (random 40) triers)))))
519       (sleep 0.5)
520       ;; Now ensure that the waiting threads will all be waked up,
521       ;; i.e. that the semaphore is still working.
522       (loop repeat (+ (count-live-threads waiters)
523                       (count-live-threads more-waiters))
524             do (signal-semaphore sem))
525       (sleep 0.5)
526       (assert (zerop (count-live-threads triers)))
527       (assert (zerop (count-live-threads waiters)))
528       (assert (zerop (count-live-threads more-waiters))))))
529
530
531
532 (format t "~&semaphore tests done~%")
533
534 (defun test-interrupt (function-to-interrupt &optional quit-p)
535   (let ((child  (make-kill-thread function-to-interrupt)))
536     ;;(format t "gdb ./src/runtime/sbcl ~A~%attach ~A~%" child child)
537     (sleep 2)
538     (format t "interrupting child ~A~%" child)
539     (interrupt-thread child
540                       (lambda ()
541                         (format t "child pid ~A~%" *current-thread*)
542                         (when quit-p (abort-thread))))
543     (sleep 1)
544     child))
545
546 ;; separate tests for (a) interrupting Lisp code, (b) C code, (c) a syscall,
547 ;; (d) waiting on a lock, (e) some code which we hope is likely to be
548 ;; in pseudo-atomic
549
550 (with-test (:name (:interrupt-thread :more-basics))
551   (let ((child (test-interrupt (lambda () (loop)))))
552     (terminate-thread child)))
553
554 (with-test (:name (:interrupt-thread :interrupt-foreign-loop))
555   (test-interrupt #'loop-forever :quit))
556
557 (with-test (:name (:interrupt-thread :interrupt-sleep))
558   (let ((child (test-interrupt (lambda () (loop (sleep 2000))))))
559     (terminate-thread child)
560     (wait-for-threads (list child))))
561
562 (with-test (:name (:interrupt-thread :interrupt-mutex-acquisition))
563   (let ((lock (make-mutex :name "loctite"))
564         child)
565     (with-mutex (lock)
566       (setf child (test-interrupt
567                    (lambda ()
568                      (with-mutex (lock)
569                        (assert (eql (mutex-value lock) *current-thread*)))
570                      (assert (not (eql (mutex-value lock) *current-thread*)))
571                      (sleep 10))))
572       ;;hold onto lock for long enough that child can't get it immediately
573       (sleep 5)
574       (interrupt-thread child (lambda () (format t "l ~A~%" (mutex-value lock))))
575       (format t "parent releasing lock~%"))
576     (terminate-thread child)
577     (wait-for-threads (list child))))
578
579 (format t "~&locking test done~%")
580
581 (defun alloc-stuff () (copy-list '(1 2 3 4 5)))
582
583 (with-test (:name (:interrupt-thread :interrupt-consing-child))
584   (let ((thread (make-thread (lambda () (loop (alloc-stuff))))))
585     (let ((killers
586            (loop repeat 4 collect
587                  (sb-thread:make-thread
588                   (lambda ()
589                     (loop repeat 25 do
590                           (sleep (random 0.1d0))
591                           (princ ".")
592                           (force-output)
593                           (sb-thread:interrupt-thread thread (lambda ()))))))))
594       (wait-for-threads killers)
595       (sb-thread:terminate-thread thread)
596       (wait-for-threads (list thread))))
597   (sb-ext:gc :full t))
598
599 (format t "~&multi interrupt test done~%")
600
601 #+(or x86 x86-64) ;; x86oid-only, see internal commentary.
602 (with-test (:name (:interrupt-thread :interrupt-consing-child :again))
603   (let ((c (make-thread (lambda () (loop (alloc-stuff))))))
604     ;; NB this only works on x86: other ports don't have a symbol for
605     ;; pseudo-atomic atomicity
606     (dotimes (i 100)
607       (sleep (random 0.1d0))
608       (interrupt-thread c
609                         (lambda ()
610                           (princ ".") (force-output)
611                           (assert (thread-alive-p *current-thread*))
612                           (assert
613                            (not (logbitp 0 SB-KERNEL:*PSEUDO-ATOMIC-BITS*))))))
614     (terminate-thread c)
615     (wait-for-threads (list c))))
616
617 (format t "~&interrupt test done~%")
618
619 (defstruct counter (n 0 :type sb-vm:word))
620 (defvar *interrupt-counter* (make-counter))
621
622 (declaim (notinline check-interrupt-count))
623 (defun check-interrupt-count (i)
624   (declare (optimize (debug 1) (speed 1)))
625   ;; This used to lose if eflags were not restored after an interrupt.
626   (unless (typep i 'fixnum)
627     (error "!!!!!!!!!!!")))
628
629 (with-test (:name (:interrupt-thread :interrupt-ATOMIC-INCF))
630   (let ((c (make-thread
631             (lambda ()
632               (handler-bind ((error #'(lambda (cond)
633                                         (princ cond)
634                                         (sb-debug:backtrace
635                                          most-positive-fixnum))))
636                 (loop (check-interrupt-count
637                        (counter-n *interrupt-counter*))))))))
638     (let ((func (lambda ()
639                   (princ ".")
640                   (force-output)
641                   (sb-ext:atomic-incf (counter-n *interrupt-counter*)))))
642       (setf (counter-n *interrupt-counter*) 0)
643       (dotimes (i 100)
644         (sleep (random 0.1d0))
645         (interrupt-thread c func))
646       (loop until (= (counter-n *interrupt-counter*) 100) do (sleep 0.1))
647       (terminate-thread c)
648       (wait-for-threads (list c)))))
649
650 (format t "~&interrupt count test done~%")
651
652 (defvar *runningp* nil)
653
654 (with-test (:name (:interrupt-thread :no-nesting))
655   (let ((thread (sb-thread:make-thread
656                  (lambda ()
657                    (catch 'xxx
658                      (loop))))))
659     (declare (special runningp))
660     (sleep 0.2)
661     (sb-thread:interrupt-thread thread
662                                 (lambda ()
663                                     (let ((*runningp* t))
664                                       (sleep 1))))
665     (sleep 0.2)
666     (sb-thread:interrupt-thread thread
667                                 (lambda ()
668                                   (throw 'xxx *runningp*)))
669     (assert (not (sb-thread:join-thread thread)))))
670
671 (with-test (:name (:interrupt-thread :nesting))
672   (let ((thread (sb-thread:make-thread
673                  (lambda ()
674                    (catch 'xxx
675                      (loop))))))
676     (declare (special runningp))
677     (sleep 0.2)
678     (sb-thread:interrupt-thread thread
679                                 (lambda ()
680                                   (let ((*runningp* t))
681                                     (sb-sys:with-interrupts
682                                       (sleep 1)))))
683     (sleep 0.2)
684     (sb-thread:interrupt-thread thread
685                                 (lambda ()
686                                   (throw 'xxx *runningp*)))
687     (assert (sb-thread:join-thread thread))))
688
689 (with-test (:name (:two-threads-running-gc))
690   (let (a-done b-done)
691     (make-join-thread (lambda ()
692                         (dotimes (i 100)
693                           (sb-ext:gc) (princ "\\") (force-output))
694                         (setf a-done t)))
695     (make-join-thread (lambda ()
696                         (dotimes (i 25)
697                           (sb-ext:gc :full t)
698                           (princ "/") (force-output))
699                         (setf b-done t)))
700     (loop
701       (when (and a-done b-done) (return))
702       (sleep 1))))
703
704 (terpri)
705
706 (defun waste (&optional (n 100000))
707   (loop repeat n do (make-string 16384)))
708
709 (with-test (:name (:one-thread-runs-gc-while-other-conses))
710   (loop for i below 100 do
711         (princ "!")
712         (force-output)
713         (make-join-thread
714          #'(lambda ()
715              (waste)))
716         (waste)
717         (sb-ext:gc)))
718
719 (terpri)
720
721 (defparameter *aaa* nil)
722 (with-test (:name (:one-thread-runs-gc-while-other-conses :again))
723   (loop for i below 100 do
724         (princ "!")
725         (force-output)
726         (make-join-thread
727          #'(lambda ()
728              (let ((*aaa* (waste)))
729                (waste))))
730         (let ((*aaa* (waste)))
731           (waste))
732         (sb-ext:gc)))
733
734 (format t "~&gc test done~%")
735
736 ;; this used to deadlock on session-lock
737 (with-test (:name (:no-session-deadlock))
738   (make-join-thread (lambda () (sb-ext:gc))))
739
740 (defun exercise-syscall (fn reference-errno)
741   (make-kill-thread
742    (lambda ()
743      (loop do
744           (funcall fn)
745           (let ((errno (sb-unix::get-errno)))
746             (sleep (random 0.1d0))
747             (unless (eql errno reference-errno)
748               (format t "Got errno: ~A (~A) instead of ~A~%"
749                       errno
750                       (sb-unix::strerror)
751                       reference-errno)
752               (force-output)
753               (abort-thread)))))))
754
755 ;; (nanosleep -1 0) does not fail on FreeBSD
756 (with-test (:name (:exercising-concurrent-syscalls))
757   (let* (#-freebsd
758          (nanosleep-errno (progn
759                             (sb-unix:nanosleep -1 0)
760                             (sb-unix::get-errno)))
761          (open-errno (progn
762                        (open "no-such-file"
763                              :if-does-not-exist nil)
764                        (sb-unix::get-errno)))
765          (threads
766           (list
767            #-freebsd
768            (exercise-syscall (lambda () (sb-unix:nanosleep -1 0)) nanosleep-errno)
769            (exercise-syscall (lambda () (open "no-such-file"
770                                               :if-does-not-exist nil))
771                              open-errno)
772            (make-join-thread (lambda () (loop (sb-ext:gc) (sleep 1)))))))
773     (sleep 10)
774     (princ "terminating threads")
775     (dolist (thread threads)
776       (sb-thread:terminate-thread thread))))
777
778 (format t "~&errno test done~%")
779
780 (with-test (:name :all-threads-have-abort-restart)
781   (loop repeat 100 do
782         (let ((thread (make-kill-thread (lambda () (sleep 0.1)))))
783           (sb-thread:interrupt-thread
784            thread
785            (lambda ()
786              (assert (find-restart 'abort)))))))
787
788 (sb-ext:gc :full t)
789
790 (format t "~&thread startup sigmask test done~%")
791
792 (with-test (:name (:debugger-no-hang-on-session-lock-if-interrupted))
793   (sb-debug::enable-debugger)
794   (let* ((main-thread *current-thread*)
795          (interruptor-thread
796           (make-thread (lambda ()
797                          (sleep 2)
798                          (interrupt-thread main-thread
799                                            (lambda ()
800                                              (with-interrupts
801                                                (break))))
802                          (sleep 2)
803                          (interrupt-thread main-thread #'continue))
804                        :name "interruptor")))
805     (with-session-lock (*session*)
806       (sleep 3))
807     (loop while (thread-alive-p interruptor-thread))))
808
809 (format t "~&session lock test done~%")
810
811 ;; expose thread creation races by exiting quickly
812 (with-test (:name (:no-thread-creation-race :light))
813   (make-join-thread (lambda ())))
814
815 (with-test (:name (:no-thread-creation-race :heavy))
816   (loop repeat 20 do
817         (wait-for-threads
818          (loop for i below 100 collect
819                (sb-thread:make-thread (lambda ()))))))
820
821 (format t "~&creation test done~%")
822
823 ;; interrupt handlers are per-thread with pthreads, make sure the
824 ;; handler installed in one thread is global
825 (with-test (:name (:global-interrupt-handler))
826   (make-join-thread
827    (lambda ()
828      (sb-ext:run-program "sleep" '("1") :search t :wait nil))))
829
830 ;;;; Binding stack safety
831
832 (defparameter *x* nil)
833 (defparameter *n-gcs-requested* 0)
834 (defparameter *n-gcs-done* 0)
835
836 (let ((counter 0))
837   (defun make-something-big ()
838     (let ((x (make-string 32000)))
839       (incf counter)
840       (let ((counter counter))
841         (sb-ext:finalize x (lambda () (format t " ~S" counter)
842                                    (force-output)))))))
843
844 (defmacro wait-for-gc ()
845   `(progn
846      (incf *n-gcs-requested*)
847      (loop while (< *n-gcs-done* *n-gcs-requested*))))
848
849 (defun send-gc ()
850   (loop until (< *n-gcs-done* *n-gcs-requested*))
851   (format t "G")
852   (force-output)
853   (sb-ext:gc)
854   (incf *n-gcs-done*))
855
856 (defun exercise-binding ()
857   (loop
858    (let ((*x* (make-something-big)))
859      (let ((*x* 42))
860        ;; at this point the binding stack looks like this:
861        ;; NO-TLS-VALUE-MARKER, *x*, SOMETHING, *x*
862        t))
863    (wait-for-gc)
864    ;; sig_stop_for_gc_handler binds FREE_INTERRUPT_CONTEXT_INDEX. By
865    ;; now SOMETHING is gc'ed and the binding stack looks like this: 0,
866    ;; 0, SOMETHING, 0 (because the symbol slots are zeroed on
867    ;; unbinding but values are not).
868    (let ((*x* nil)
869          (binding-pointer-delta (ash 2 (- sb-vm:word-shift sb-vm:n-fixnum-tag-bits))))
870      ;; bump bsp as if a BIND had just started
871      (incf sb-vm::*binding-stack-pointer* binding-pointer-delta)
872      (wait-for-gc)
873      (decf sb-vm::*binding-stack-pointer* binding-pointer-delta))))
874
875 (with-test (:name (:binding-stack-gc-safety))
876   (let (threads)
877     (unwind-protect
878          (progn
879            (push (make-kill-thread #'exercise-binding) threads)
880            (push (make-kill-thread (lambda ()
881                                      (loop
882                                       (sleep 0.1)
883                                       (send-gc))))
884                  threads)
885            (sleep 4))
886       (mapc #'sb-thread:terminate-thread threads))))
887
888 (format t "~&binding test done~%")
889
890 ;;; HASH TABLES
891
892 (defvar *errors* nil)
893
894 (defun oops (e)
895   (setf *errors* e)
896   (format t "~&oops: ~A in ~S~%" e *current-thread*)
897   (sb-debug:backtrace)
898   (catch 'done))
899
900 (with-test (:name (:unsynchronized-hash-table)
901                   ;; FIXME: This test occasionally eats out craploads
902                   ;; of heap instead of expected error early. Not 100%
903                   ;; sure if it would finish as expected, but since it
904                   ;; hits swap on my system I'm not likely to find out
905                   ;; soon. Disabling for now. -- nikodemus
906             :skipped-on :sbcl)
907   ;; We expect a (probable) error here: parellel readers and writers
908   ;; on a hash-table are not expected to work -- but we also don't
909   ;; expect this to corrupt the image.
910   (let* ((hash (make-hash-table))
911          (*errors* nil)
912          (threads (list (make-kill-thread
913                          (lambda ()
914                            (catch 'done
915                              (handler-bind ((serious-condition 'oops))
916                                (loop
917                                  ;;(princ "1") (force-output)
918                                  (setf (gethash (random 100) hash) 'h)))))
919                          :name "writer")
920                         (make-kill-thread
921                          (lambda ()
922                            (catch 'done
923                              (handler-bind ((serious-condition 'oops))
924                                (loop
925                                  ;;(princ "2") (force-output)
926                                  (remhash (random 100) hash)))))
927                          :name "reader")
928                         (make-kill-thread
929                          (lambda ()
930                            (catch 'done
931                              (handler-bind ((serious-condition 'oops))
932                                (loop
933                                  (sleep (random 1.0))
934                                  (sb-ext:gc :full t)))))
935                          :name "collector"))))
936     (unwind-protect
937          (sleep 10)
938       (mapc #'sb-thread:terminate-thread threads))))
939
940 (format t "~&unsynchronized hash table test done~%")
941
942 (with-test (:name (:synchronized-hash-table))
943   (let* ((hash (make-hash-table :synchronized t))
944          (*errors* nil)
945          (threads (list (make-kill-thread
946                          (lambda ()
947                            (catch 'done
948                              (handler-bind ((serious-condition 'oops))
949                                (loop
950                                  ;;(princ "1") (force-output)
951                                  (setf (gethash (random 100) hash) 'h)))))
952                          :name "writer")
953                         (make-kill-thread
954                          (lambda ()
955                            (catch 'done
956                              (handler-bind ((serious-condition 'oops))
957                                (loop
958                                  ;;(princ "2") (force-output)
959                                  (remhash (random 100) hash)))))
960                          :name "reader")
961                         (make-kill-thread
962                          (lambda ()
963                            (catch 'done
964                              (handler-bind ((serious-condition 'oops))
965                                (loop
966                                  (sleep (random 1.0))
967                                  (sb-ext:gc :full t)))))
968                          :name "collector"))))
969     (unwind-protect
970          (sleep 10)
971       (mapc #'sb-thread:terminate-thread threads))
972     (assert (not *errors*))))
973
974 (format t "~&synchronized hash table test done~%")
975
976 (with-test (:name (:hash-table-parallel-readers))
977   (let ((hash (make-hash-table))
978         (*errors* nil))
979     (loop repeat 50
980           do (setf (gethash (random 100) hash) 'xxx))
981     (let ((threads (list (make-kill-thread
982                           (lambda ()
983                             (catch 'done
984                               (handler-bind ((serious-condition 'oops))
985                                 (loop
986                                       until (eq t (gethash (random 100) hash))))))
987                           :name "reader 1")
988                          (make-kill-thread
989                           (lambda ()
990                             (catch 'done
991                               (handler-bind ((serious-condition 'oops))
992                                 (loop
993                                       until (eq t (gethash (random 100) hash))))))
994                           :name "reader 2")
995                          (make-kill-thread
996                           (lambda ()
997                             (catch 'done
998                               (handler-bind ((serious-condition 'oops))
999                                 (loop
1000                                       until (eq t (gethash (random 100) hash))))))
1001                           :name "reader 3")
1002                          (make-kill-thread
1003                           (lambda ()
1004                             (catch 'done
1005                               (handler-bind ((serious-condition 'oops))
1006                                (loop
1007                                  (sleep (random 1.0))
1008                                  (sb-ext:gc :full t)))))
1009                           :name "collector"))))
1010       (unwind-protect
1011            (sleep 10)
1012         (mapc #'sb-thread:terminate-thread threads))
1013       (assert (not *errors*)))))
1014
1015 (format t "~&multiple reader hash table test done~%")
1016
1017 (with-test (:name (:hash-table-single-accessor-parallel-gc))
1018   (let ((hash (make-hash-table))
1019         (*errors* nil))
1020     (let ((threads (list (make-kill-thread
1021                           (lambda ()
1022                             (handler-bind ((serious-condition 'oops))
1023                               (loop
1024                                 (let ((n (random 100)))
1025                                   (if (gethash n hash)
1026                                       (remhash n hash)
1027                                       (setf (gethash n hash) 'h))))))
1028                           :name "accessor")
1029                          (make-kill-thread
1030                           (lambda ()
1031                             (handler-bind ((serious-condition 'oops))
1032                               (loop
1033                                 (sleep (random 1.0))
1034                                 (sb-ext:gc :full t))))
1035                           :name "collector"))))
1036       (unwind-protect
1037            (sleep 10)
1038         (mapc #'sb-thread:terminate-thread threads))
1039       (assert (not *errors*)))))
1040
1041 (format t "~&single accessor hash table test~%")
1042
1043 #|  ;; a cll post from eric marsden
1044 | (defun crash ()
1045 |   (setq *debugger-hook*
1046 |         (lambda (condition old-debugger-hook)
1047 |           (debug:backtrace 10)
1048 |           (unix:unix-exit 2)))
1049 |   #+live-dangerously
1050 |   (mp::start-sigalrm-yield)
1051 |   (flet ((roomy () (loop (with-output-to-string (*standard-output*) (room)))))
1052 |     (mp:make-process #'roomy)
1053 |     (mp:make-process #'roomy)))
1054 |#
1055
1056 (with-test (:name (:condition-variable :notify-multiple))
1057   (flet ((tester (notify-fun)
1058            (let ((queue (make-waitqueue :name "queue"))
1059                  (lock (make-mutex :name "lock"))
1060                  (data nil))
1061              (labels ((test (x)
1062                         (loop
1063                            (with-mutex (lock)
1064                              (format t "condition-wait ~a~%" x)
1065                              (force-output)
1066                              (condition-wait queue lock)
1067                              (format t "woke up ~a~%" x)
1068                              (force-output)
1069                              (push x data)))))
1070                (let ((threads (loop for x from 1 to 10
1071                                     collect
1072                                     (let ((x x))
1073                                       (make-kill-thread (lambda ()
1074                                                           (test x)))))))
1075                  (sleep 5)
1076                  (with-mutex (lock)
1077                    (funcall notify-fun queue))
1078                  (sleep 5)
1079                  (mapcar #'terminate-thread threads)
1080                  ;; Check that all threads woke up at least once
1081                  (assert (= (length (remove-duplicates data)) 10)))))))
1082     (tester (lambda (queue)
1083               (format t "~&(condition-notify queue 10)~%")
1084               (force-output)
1085               (condition-notify queue 10)))
1086     (tester (lambda (queue)
1087               (format t "~&(condition-broadcast queue)~%")
1088               (force-output)
1089               (condition-broadcast queue)))))
1090
1091 (format t "waitqueue wakeup tests done~%")
1092
1093 ;;; Make sure that a deadline handler is not invoked twice in a row in
1094 ;;; CONDITION-WAIT. See LP #512914 for a detailed explanation.
1095 ;;;
1096 (with-test (:name (:condition-wait :deadlines :LP-512914))
1097   (let ((n 2)                      ; was empirically enough to trigger the bug
1098         (mutex (sb-thread:make-mutex))
1099         (waitq (sb-thread:make-waitqueue))
1100         (threads nil)
1101         (deadline-handler-run-twice? nil))
1102     (dotimes (i n)
1103       (let ((child
1104               (sb-thread:make-thread
1105                #'(lambda ()
1106                    (handler-bind
1107                        ((sb-sys:deadline-timeout
1108                           (let ((already? nil))
1109                             #'(lambda (c)
1110                                 (when already?
1111                                   (setq deadline-handler-run-twice? t))
1112                                 (setq already? t)
1113                                 (sleep 0.2)
1114                                 (sb-thread:condition-broadcast waitq)
1115                                 (sb-sys:defer-deadline 10.0 c)))))
1116                      (sb-sys:with-deadline (:seconds 0.1)
1117                        (sb-thread:with-mutex (mutex)
1118                          (sb-thread:condition-wait waitq mutex))))))))
1119         (push child threads)))
1120     (mapc #'sb-thread:join-thread threads)
1121     (assert (not deadline-handler-run-twice?))))
1122
1123 (with-test (:name (:condition-wait :signal-deadline-with-interrupts-enabled))
1124   (let ((mutex (sb-thread:make-mutex))
1125         (waitq (sb-thread:make-waitqueue))
1126         (A-holds? :unknown)
1127         (B-holds? :unknown)
1128         (A-interrupts-enabled? :unknown)
1129         (B-interrupts-enabled? :unknown)
1130         (A)
1131         (B))
1132     ;; W.L.O.G., we assume that A is executed first...
1133     (setq A (sb-thread:make-thread
1134              #'(lambda ()
1135                  (handler-bind
1136                      ((sb-sys:deadline-timeout
1137                        #'(lambda (c)
1138                            ;; We came here through the call to DECODE-TIMEOUT
1139                            ;; in CONDITION-WAIT; hence both here are supposed
1140                            ;; to evaluate to T.
1141                            (setq A-holds? (sb-thread:holding-mutex-p mutex))
1142                            (setq A-interrupts-enabled?
1143                                  sb-sys:*interrupts-enabled*)
1144                            (sleep 0.2)
1145                            (sb-thread:condition-broadcast waitq)
1146                            (sb-sys:defer-deadline 10.0 c))))
1147                    (sb-sys:with-deadline (:seconds 0.1)
1148                      (sb-thread:with-mutex (mutex)
1149                        (sb-thread:condition-wait waitq mutex)))))
1150              :name "A"))
1151     (setq B (sb-thread:make-thread
1152              #'(lambda ()
1153                  (thread-yield)
1154                  (handler-bind
1155                      ((sb-sys:deadline-timeout
1156                        #'(lambda (c)
1157                            ;; We came here through the call to DECODE-TIMEOUT
1158                            ;; in CONDITION-WAIT (contended case of
1159                            ;; reaquiring the mutex) - so the former will
1160                            ;; be NIL, but interrupts should still be enabled.
1161                            (setq B-holds? (sb-thread:holding-mutex-p mutex))
1162                            (setq B-interrupts-enabled?
1163                                  sb-sys:*interrupts-enabled*)
1164                            (sleep 0.2)
1165                            (sb-thread:condition-broadcast waitq)
1166                            (sb-sys:defer-deadline 10.0 c))))
1167                    (sb-sys:with-deadline (:seconds 0.1)
1168                      (sb-thread:with-mutex (mutex)
1169                        (sb-thread:condition-wait waitq mutex)))))
1170              :name "B"))
1171     (sb-thread:join-thread A)
1172     (sb-thread:join-thread B)
1173     (let ((A-result (list A-holds? A-interrupts-enabled?))
1174           (B-result (list B-holds? B-interrupts-enabled?)))
1175       ;; We also check some subtle behaviour w.r.t. whether a deadline
1176       ;; handler in CONDITION-WAIT got the mutex, or not. This is most
1177       ;; probably very internal behaviour (so user should not depend
1178       ;; on it) -- I added the testing here just to manifest current
1179       ;; behaviour.
1180       (cond ((equal A-result '(t t)) (assert (equal B-result '(nil t))))
1181             ((equal B-result '(t t)) (assert (equal A-result '(nil t))))
1182             (t
1183              (error "Failure: fell through wit A: ~S, B: ~S"
1184                     A-result
1185                     B-result))))))
1186
1187 (with-test (:name (:mutex :finalization))
1188   (let ((a nil))
1189     (dotimes (i 500000)
1190       (setf a (make-mutex)))))
1191
1192 (format t "mutex finalization test done~%")
1193
1194 ;;; Check that INFO is thread-safe, at least when we're just doing reads.
1195
1196 (let* ((symbols (loop repeat 10000 collect (gensym)))
1197        (functions (loop for (symbol . rest) on symbols
1198                         for next = (car rest)
1199                         for fun = (let ((next next))
1200                                     (lambda (n)
1201                                       (if next
1202                                           (funcall next (1- n))
1203                                           n)))
1204                         do (setf (symbol-function symbol) fun)
1205                         collect fun)))
1206   (defun infodb-test ()
1207     (funcall (car functions) 9999)))
1208
1209 (with-test (:name (:infodb :read))
1210   (let* ((ok t)
1211          (threads (loop for i from 0 to 10
1212                         collect (sb-thread:make-thread
1213                                  (lambda ()
1214                                    (dotimes (j 100)
1215                                      (write-char #\-)
1216                                      (finish-output)
1217                                      (let ((n (infodb-test)))
1218                                        (unless (zerop n)
1219                                          (setf ok nil)
1220                                          (format t "N != 0 (~A)~%" n)
1221                                          (abort-thread)))))))))
1222     (wait-for-threads threads)
1223     (assert ok)))
1224
1225 (format t "infodb test done~%")
1226
1227 (with-test (:name :backtrace)
1228   ;; Printing backtraces from several threads at once used to hang the
1229   ;; whole SBCL process (discovered by accident due to a timer.impure
1230   ;; test misbehaving). The cause was that packages weren't even
1231   ;; thread-safe for only doing FIND-SYMBOL, and while printing
1232   ;; backtraces a loot of symbol lookups need to be done due to
1233   ;; *PRINT-ESCAPE*.
1234   (let* ((threads (loop repeat 10
1235                         collect (sb-thread:make-thread
1236                                  (lambda ()
1237                                    (dotimes (i 1000)
1238                                      (with-output-to-string (*debug-io*)
1239                                        (sb-debug::backtrace 10))))))))
1240     (wait-for-threads threads)))
1241
1242 (format t "backtrace test done~%")
1243
1244 (format t "~&starting gc deadlock test: WARNING: THIS TEST WILL HANG ON FAILURE!~%")
1245
1246 (with-test (:name :gc-deadlock)
1247   ;; Prior to 0.9.16.46 thread exit potentially deadlocked the
1248   ;; GC due to *all-threads-lock* and session lock. On earlier
1249   ;; versions and at least on one specific box this test is good enough
1250   ;; to catch that typically well before the 1500th iteration.
1251   (loop
1252      with i = 0
1253      with n = 3000
1254      while (< i n)
1255      do
1256        (incf i)
1257        (when (zerop (mod i 100))
1258          (write-char #\.)
1259          (force-output))
1260        (handler-case
1261            (if (oddp i)
1262                (make-join-thread
1263                 (lambda ()
1264                   (sleep (random 0.001)))
1265                 :name (format nil "SLEEP-~D" i))
1266                (make-join-thread
1267                 (lambda ()
1268                   ;; KLUDGE: what we are doing here is explicit,
1269                   ;; but the same can happen because of a regular
1270                   ;; MAKE-THREAD or LIST-ALL-THREADS, and various
1271                   ;; session functions.
1272                   (sb-thread::with-all-threads-lock
1273                     (sb-thread::with-session-lock (sb-thread::*session*)
1274                       (sb-ext:gc))))
1275                 :name (format nil "GC-~D" i)))
1276          (error (e)
1277            (format t "~%error creating thread ~D: ~A -- backing off for retry~%" i e)
1278            (sleep 0.1)
1279            (incf i)))))
1280
1281 (format t "~&gc deadlock test done~%")
1282 \f
1283 (let ((count (make-array 8 :initial-element 0)))
1284   (defun closure-one ()
1285     (declare (optimize safety))
1286     (values (incf (aref count 0)) (incf (aref count 1))
1287             (incf (aref count 2)) (incf (aref count 3))
1288             (incf (aref count 4)) (incf (aref count 5))
1289             (incf (aref count 6)) (incf (aref count 7))))
1290   (defun no-optimizing-away-closure-one ()
1291     (setf count (make-array 8 :initial-element 0))))
1292
1293 (defstruct box
1294   (count 0))
1295
1296 (let ((one (make-box))
1297       (two (make-box))
1298       (three (make-box)))
1299   (defun closure-two ()
1300     (declare (optimize safety))
1301     (values (incf (box-count one)) (incf (box-count two)) (incf (box-count three))))
1302   (defun no-optimizing-away-closure-two ()
1303     (setf one (make-box)
1304           two (make-box)
1305           three (make-box))))
1306
1307 (with-test (:name (:funcallable-instances))
1308   ;; the funcallable-instance implementation used not to be threadsafe
1309   ;; against setting the funcallable-instance function to a closure
1310   ;; (because the code and lexenv were set separately).
1311   (let ((fun (sb-kernel:%make-funcallable-instance 0))
1312         (condition nil))
1313     (setf (sb-kernel:funcallable-instance-fun fun) #'closure-one)
1314     (flet ((changer ()
1315              (loop (setf (sb-kernel:funcallable-instance-fun fun) #'closure-one)
1316                    (setf (sb-kernel:funcallable-instance-fun fun) #'closure-two)))
1317            (test ()
1318              (handler-case (loop (funcall fun))
1319                (serious-condition (c) (setf condition c)))))
1320       (let ((changer (make-thread #'changer))
1321             (test (make-thread #'test)))
1322         (handler-case
1323             (progn
1324               ;; The two closures above are fairly carefully crafted
1325               ;; so that if given the wrong lexenv they will tend to
1326               ;; do some serious damage, but it is of course difficult
1327               ;; to predict where the various bits and pieces will be
1328               ;; allocated.  Five seconds failed fairly reliably on
1329               ;; both my x86 and x86-64 systems.  -- CSR, 2006-09-27.
1330               (sb-ext:with-timeout 5
1331                 (wait-for-threads (list test)))
1332               (error "~@<test thread got condition:~2I~_~A~@:>" condition))
1333           (sb-ext:timeout ()
1334             (terminate-thread changer)
1335             (terminate-thread test)
1336             (wait-for-threads (list changer test))))))))
1337
1338 (format t "~&funcallable-instance test done~%")
1339
1340 (defun random-type (n)
1341   `(integer ,(random n) ,(+ n (random n))))
1342
1343 (defun subtypep-hash-cache-test ()
1344   (dotimes (i 10000)
1345     (let ((type1 (random-type 500))
1346           (type2 (random-type 500)))
1347       (let ((a (subtypep type1 type2)))
1348         (dotimes (i 100)
1349           (assert (eq (subtypep type1 type2) a))))))
1350   (format t "ok~%")
1351   (force-output))
1352
1353 (with-test (:name (:hash-cache :subtypep))
1354   (mapc #'join-thread
1355         (loop repeat 10
1356               collect (sb-thread:make-thread #'subtypep-hash-cache-test))))
1357 (format t "hash-cache tests done~%")
1358
1359 ;;;; BLACK BOX TESTS
1360
1361 (in-package :cl-user)
1362 (use-package :test-util)
1363 (use-package "ASSERTOID")
1364
1365 (format t "parallel defclass test -- WARNING, WILL HANG ON FAILURE!~%")
1366 (with-test (:name :parallel-defclass)
1367   (defclass test-1 () ((a :initform :orig-a)))
1368   (defclass test-2 () ((b :initform :orig-b)))
1369   (defclass test-3 (test-1 test-2) ((c :initform :orig-c)))
1370   (let* ((run t)
1371          (d1 (sb-thread:make-thread (lambda ()
1372                                       (loop while run
1373                                             do (defclass test-1 () ((a :initform :new-a)))
1374                                             (write-char #\1)
1375                                             (force-output)))
1376                                     :name "d1"))
1377          (d2 (sb-thread:make-thread (lambda ()
1378                                       (loop while run
1379                                             do (defclass test-2 () ((b :initform :new-b)))
1380                                                (write-char #\2)
1381                                                (force-output)))
1382                                     :name "d2"))
1383          (d3 (sb-thread:make-thread (lambda ()
1384                                       (loop while run
1385                                             do (defclass test-3 (test-1 test-2) ((c :initform :new-c)))
1386                                                (write-char #\3)
1387                                                (force-output)))
1388                                     :name "d3"))
1389          (i (sb-thread:make-thread (lambda ()
1390                                      (loop while run
1391                                            do (let ((i (make-instance 'test-3)))
1392                                                 (assert (member (slot-value i 'a) '(:orig-a :new-a)))
1393                                                 (assert (member (slot-value i 'b) '(:orig-b :new-b)))
1394                                                 (assert (member (slot-value i 'c) '(:orig-c :new-c))))
1395                                               (write-char #\i)
1396                                               (force-output)))
1397                                    :name "i")))
1398     (format t "~%sleeping!~%")
1399     (sleep 2.0)
1400     (format t "~%stopping!~%")
1401     (setf run nil)
1402     (mapc (lambda (th)
1403             (sb-thread:join-thread th)
1404             (format t "~%joined ~S~%" (sb-thread:thread-name th)))
1405           (list d1 d2 d3 i))))
1406 (format t "parallel defclass test done~%")
1407
1408 (with-test (:name (:deadlock-detection :interrupts))
1409   (let* ((m1 (sb-thread:make-mutex :name "M1"))
1410          (m2 (sb-thread:make-mutex :name "M2"))
1411          (t1-can-go (sb-thread:make-semaphore :name "T1 can go"))
1412          (t2-can-go (sb-thread:make-semaphore :name "T2 can go"))
1413          (t1 (sb-thread:make-thread
1414               (lambda ()
1415                 (sb-thread:with-mutex (m1)
1416                   (sb-thread:wait-on-semaphore t1-can-go)
1417                   :ok1))
1418               :name "T1"))
1419          (t2 (sb-thread:make-thread
1420               (lambda ()
1421                 (sb-ext:wait-for (eq t1 (sb-thread:mutex-owner m1)))
1422                 (sb-thread:with-mutex (m1 :wait-p t)
1423                   (sb-thread:wait-on-semaphore t2-can-go)
1424                   :ok2))
1425               :name "T2")))
1426     (sb-ext:wait-for (eq m1 (sb-thread::thread-waiting-for t2)))
1427     (sb-thread:interrupt-thread t2 (lambda ()
1428                                      (sb-thread:with-mutex (m2 :wait-p t)
1429                                        (sb-ext:wait-for
1430                                         (eq m2 (sb-thread::thread-waiting-for t1)))
1431                                        (sb-thread:signal-semaphore t2-can-go))))
1432     (sb-ext:wait-for (eq t2 (sb-thread:mutex-owner m2)))
1433     (sb-thread:interrupt-thread t1 (lambda ()
1434                                      (sb-thread:with-mutex (m2 :wait-p t)
1435                                        (sb-thread:signal-semaphore t1-can-go))))
1436     ;; both threads should finish without a deadlock or deadlock
1437     ;; detection error
1438     (let ((res (list (sb-thread:join-thread t1)
1439                      (sb-thread:join-thread t2))))
1440       (assert (equal '(:ok1 :ok2) res)))))
1441
1442 (with-test (:name (:deadlock-detection :gc))
1443   ;; To semi-reliably trigger the error (in SBCL's where)
1444   ;; it was present you had to run this for > 30 seconds,
1445   ;; but that's a bit long for a single test.
1446   (let* ((stop (+ 5 (get-universal-time)))
1447          (m1 (sb-thread:make-mutex :name "m1"))
1448          (t1 (sb-thread:make-thread
1449               (lambda ()
1450                 (loop until (> (get-universal-time) stop)
1451                       do (sb-thread:with-mutex (m1)
1452                            (eval `(make-array 24))))
1453                 :ok)))
1454          (t2 (sb-thread:make-thread
1455               (lambda ()
1456                 (loop until (> (get-universal-time) stop)
1457                       do (sb-thread:with-mutex (m1)
1458                            (eval `(make-array 24))))
1459                 :ok))))
1460     (let ((res (list (sb-thread:join-thread t1)
1461                      (sb-thread:join-thread t2))))
1462       (assert (equal '(:ok :ok) res)))))
1463
1464 (with-test (:name :spinlock-api)
1465   (let* ((warned 0)
1466          (funs
1467            (handler-bind ((sb-int:early-deprecation-warning (lambda (_)
1468                                                               (declare (ignore _))
1469                                                               (incf warned))))
1470              (list (compile nil `(lambda (lock)
1471                                    (sb-thread::with-spinlock (lock)
1472                                      t)))
1473                    (compile nil `(lambda ()
1474                                    (sb-thread::make-spinlock :name "foo")))
1475                    (compile nil `(lambda (lock)
1476                                    (sb-thread::get-spinlock lock)))
1477                    (compile nil `(lambda (lock)
1478                                    (sb-thread::release-spinlock lock)))))))
1479     (assert (eql 4 warned))
1480     (handler-bind ((warning #'error))
1481       (destructuring-bind (with make get release) funs
1482         (let ((lock (funcall make)))
1483           (funcall get lock)
1484           (funcall release lock)
1485           (assert (eq t (funcall with lock))))))))