1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; While most of SBCL is derived from the CMU CL system, the test
5 ;;;; files (like this one) were written from scratch after the fork
8 ;;;; This software is in the public domain and is provided with
9 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
10 ;;;; more information.
12 #+interpreter
(sb-ext:exit
:code
104)
14 (in-package "CL-USER")
16 (use-package :test-util
)
18 (with-test (:name
:heap
)
20 (heap (make-array size
:adjustable t
:fill-pointer
0))
21 (unsorted (loop for i below size collect
(random size
)))
22 (sorted (sort (copy-list unsorted
) #'>=))
24 (map nil
#'(lambda (val) (sb-impl::heap-insert heap val
)) unsorted
)
25 (setf heap-sorted
(loop for i below size
26 collect
(sb-impl::heap-extract-maximum heap
)))
27 (unless (equal sorted heap-sorted
)
28 (error "Heap sort failure ~S" heap-sorted
))))
30 (sb-alien:define-alien-routine
"check_deferrables_blocked_or_lose"
32 (where sb-alien
:unsigned-long
))
33 (sb-alien:define-alien-routine
"check_deferrables_unblocked_or_lose"
35 (where sb-alien
:unsigned-long
))
37 (defun make-limited-timer (fn n
&rest args
)
40 (apply #'sb-ext
:make-timer
42 (sb-sys:without-interrupts
45 (warn "Unscheduling timer ~A ~
46 upon reaching run limit. System too slow?"
48 (sb-ext:unschedule-timer timer
))
50 (sb-sys:allow-with-interrupts
54 (defun make-and-schedule-and-wait (fn time
)
55 (let ((finishedp nil
))
56 (sb-ext:schedule-timer
(sb-ext:make-timer
58 (sb-sys:without-interrupts
60 (sb-sys:allow-with-interrupts
62 (setq finishedp t
)))))
64 (loop until finishedp
)))
66 (with-test (:name
(:timer
:deferrables-blocked
) :skipped-on
:win32
)
67 (make-and-schedule-and-wait (lambda ()
68 (check-deferrables-blocked-or-lose 0))
70 (check-deferrables-unblocked-or-lose 0))
72 (with-test (:name
(:timer
:deferrables-unblocked
) :skipped-on
:win32
)
73 (make-and-schedule-and-wait (lambda ()
74 (sb-sys:with-interrupts
75 (check-deferrables-unblocked-or-lose 0)))
77 (check-deferrables-unblocked-or-lose 0))
79 (with-test (:name
(:timer
:deferrables-unblocked
:unwind
) :skipped-on
:win32
)
81 (make-and-schedule-and-wait (lambda ()
82 (check-deferrables-blocked-or-lose 0)
86 (check-deferrables-unblocked-or-lose 0))
88 (defmacro raises-timeout-p
(&body body
)
89 `(handler-case (progn (progn ,@body
) nil
)
90 (sb-ext:timeout
() t
)))
92 (with-test (:name
(:timer
:relative
)
93 :fails-on
'(and :sparc
:linux
)
95 (let* ((has-run-p nil
)
96 (timer (make-timer (lambda () (setq has-run-p t
))
97 :name
"simple timer")))
98 (schedule-timer timer
0.5)
100 (assert (not has-run-p
))
103 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
105 (with-test (:name
(:timer
:absolute
)
106 :fails-on
'(and :sparc
:linux
)
108 (let* ((has-run-p nil
)
109 (timer (make-timer (lambda () (setq has-run-p t
))
110 :name
"simple timer")))
111 (schedule-timer timer
(+ 1/2 (get-universal-time)) :absolute-p t
)
113 (assert (not has-run-p
))
116 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
118 (with-test (:name
(:timer
:other-thread
) :skipped-on
'(not :sb-thread
))
119 (let* ((thread (make-kill-thread (lambda () (sleep 2))))
120 (timer (make-timer (lambda ()
121 (assert (eq thread sb-thread
:*current-thread
*)))
123 (schedule-timer timer
0.1)))
125 (with-test (:name
(:timer
:new-thread
) :skipped-on
'(not :sb-thread
))
126 (let* ((original-thread sb-thread
:*current-thread
*)
129 (assert (not (eq original-thread
130 sb-thread
:*current-thread
*))))
132 (schedule-timer timer
0.1)))
134 (with-test (:name
(:timer
:repeat-and-unschedule
)
135 :fails-on
'(and :sparc
:linux
)
140 (make-timer (lambda ()
141 (when (= 5 (incf run-count
))
142 (unschedule-timer timer
)))))
143 (schedule-timer timer
0 :repeat-interval
0.2)
144 (assert (timer-scheduled-p timer
:delta
0.3))
146 (assert (= 5 run-count
))
147 (assert (not (timer-scheduled-p timer
)))
148 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
150 (with-test (:name
(:timer
:reschedule
) :skipped-on
:win32
)
151 (let* ((has-run-p nil
)
152 (timer (make-timer (lambda ()
153 (setq has-run-p t
)))))
154 (schedule-timer timer
0.2)
155 (schedule-timer timer
0.3)
158 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
160 (with-test (:name
(:timer
:stress
) :skipped-on
:win32
)
161 (let ((time (1+ (get-universal-time))))
163 (schedule-timer (make-timer (lambda ())) time
:absolute-p t
))
165 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
167 (with-test (:name
(:timer
:stress2
) :skipped-on
:win32
)
168 (let ((time (1+ (get-universal-time)))
170 (loop for time-n from time upto
(+ 1/10 time
) by
(/ 1/10 200)
171 do
(schedule-timer (make-timer (lambda ())) time-n
:absolute-p t
)
174 (assert (zerop (length (sb-impl::%pqueue-contents sb-impl
::*schedule
*))))))
176 (with-test (:name
(:with-timeout
:timeout
) :skipped-on
:win32
)
177 (assert (raises-timeout-p
178 (sb-ext:with-timeout
0.2
181 (with-test (:name
(:with-timeout
:fall-through
) :skipped-on
:win32
)
182 (assert (not (raises-timeout-p
183 (sb-ext:with-timeout
0.3
186 (with-test (:name
(:with-timeout
:nested-timeout-smaller
) :skipped-on
:win32
)
187 (assert(raises-timeout-p
188 (sb-ext:with-timeout
10
189 (sb-ext:with-timeout
0.5
192 (with-test (:name
(:with-timeout
:nested-timeout-bigger
) :skipped-on
:win32
)
193 (assert(raises-timeout-p
194 (sb-ext:with-timeout
0.5
195 (sb-ext:with-timeout
2
198 (defun wait-for-threads (threads)
199 (loop while
(some #'sb-thread
:thread-alive-p threads
) do
(sleep 0.01)))
201 (with-test (:name
(:with-timeout
:many-at-the-same-time
)
202 :skipped-on
'(not :sb-thread
))
204 (let ((threads (loop repeat
10 collect
205 (sb-thread:make-thread
208 (sb-ext:with-timeout
0.5
211 (format t
"~%not ok~%"))
214 (assert (not (raises-timeout-p
215 (sb-ext:with-timeout
20
216 (wait-for-threads threads
)))))
219 (with-test (:name
(:with-timeout
:dead-thread
) :skipped-on
'(not :sb-thread
))
222 (let ((timer (make-timer (lambda ()))))
223 (schedule-timer timer
3)
229 (defun random-type (n)
230 `(integer ,(random n
) ,(+ n
(random n
))))
232 ;;; FIXME: Since timeouts do not work on Windows this would loop
234 (with-test (:name
(:hash-cache
:interrupt
) :skipped-on
:win32
)
235 (let* ((type1 (random-type 500))
236 (type2 (random-type 500))
237 (wanted (subtypep type1 type2
)))
240 (sb-ext:schedule-timer
(sb-ext:make-timer
242 (assert (eq wanted
(subtypep type1 type2
)))
246 (assert (eq wanted
(subtypep type1 type2
))))))))
248 ;;; Used to hang occasionally at least on x86. Two bugs caused it:
249 ;;; running out of stack (due to repeating timers being rescheduled
250 ;;; before they ran) and dying threads were open interrupts.
251 (with-test (:name
(:timer
:parallel-unschedule
)
252 :skipped-on
'(not :sb-thread
)
254 (let ((timer (sb-ext:make-timer
(lambda () 42) :name
"parallel schedulers"))
257 (sleep (random 0.01))
259 do
(sb-ext:unschedule-timer timer
))))
260 (sb-sys:with-deadline
(:seconds
30)
262 do
(mapcar #'sb-thread
:join-thread
263 (loop for i from
1 upto
10
264 collect
(let* ((thread (sb-thread:make-thread
#'flop
265 :name
(format nil
"scheduler ~A" i
)))
266 (ticker (make-limited-timer (lambda () 13)
268 :thread
(or other thread
)
269 :name
(format nil
"ticker ~A" i
))))
271 (sb-ext:schedule-timer ticker
0 :repeat-interval
0.00001)
274 ;;;; FIXME: OS X 10.4 doesn't like these being at all, and gives us a SIGSEGV
275 ;;;; instead of using the Mach expection system! 10.5 on the other tends to
276 ;;;; lose() here with interrupt already pending. :/
278 ;;;; Used to have problems in genereal, see comment on (:TIMER
279 ;;;; :PARALLEL-UNSCHEDULE).
280 (with-test (:name
(:timer
:schedule-stress
) :skipped-on
:win32
)
283 (loop for i from
1 upto
1
284 collect
(make-limited-timer
287 :name
(format nil
"slow ~A" i
))))
288 (fast-timer (make-limited-timer (lambda () 42) 1000
290 (sb-ext:schedule-timer fast-timer
0.0001 :repeat-interval
0.0001)
291 (dolist (timer slow-timers
)
292 (sb-ext:schedule-timer timer
(random 0.1)
293 :repeat-interval
(random 0.1)))
294 (dolist (timer slow-timers
)
295 (sb-ext:unschedule-timer timer
))
296 (sb-ext:unschedule-timer fast-timer
))))
298 (mapcar #'sb-thread
:join-thread
299 (loop repeat
10 collect
(sb-thread:make-thread
#'test
)))
301 (loop repeat
10 do
(test))))
303 (with-test (:name
(:timer
:threaded-stress
)
304 :skipped-on
'(not :sb-thread
)
308 (let ((barrier (sb-thread:make-semaphore
))
310 (flet ((wait-for-goal ()
312 (declare (special *n
*))
313 (sb-thread:signal-semaphore barrier
)
314 (loop until
(eql *n
* goal
))))
316 (declare (special *n
*))
318 (let ((threads (list (sb-thread:make-thread
#'wait-for-goal
)
319 (sb-thread:make-thread
#'wait-for-goal
)
320 (sb-thread:make-thread
#'wait-for-goal
))))
321 (sb-thread:wait-on-semaphore barrier
)
322 (sb-thread:wait-on-semaphore barrier
)
323 (sb-thread:wait-on-semaphore barrier
)
324 (flet ((sched (thread)
325 (sb-thread:make-thread
(lambda ()
327 do
(sb-ext:schedule-timer
(make-timer #'one
:thread thread
) 0.001))))))
328 (dolist (thread threads
)
330 (mapcar #'sb-thread
:join-thread threads
)))))
332 ;; SB-THREAD:MAKE-THREAD used to lock SB-THREAD:*MAKE-THREAD-LOCK*
333 ;; before entering WITHOUT-INTERRUPTS. When a thread which was
334 ;; executing SB-THREAD:MAKE-THREAD was interrupted with code which
335 ;; also called SB-THREAD:MAKE-THREAD, it could happen that the first
336 ;; thread already owned SB-THREAD:*MAKE-THREAD-LOCK* and the
337 ;; interrupting code thus made a recursive lock attempt. A timer with
338 ;; :THREAD T or :THREAD <some thread spawning child threads> could
339 ;; also trigger this problem.
341 ;; See (MAKE-THREAD :INTERRUPT-WITH MAKE-THREAD :BUG-1180102) in
342 ;; threads.pure.lisp.
343 (with-test (:name
(:timer
:dispatch-thread
:make-thread
:bug-1180102
)
344 :skipped-on
'(not :sb-thread
))
345 (flet ((test (thread)
346 (let ((timer (make-timer (lambda ()) :thread thread
)))
347 (schedule-timer timer
.01 :repeat-interval
0.1)
351 (push (sb-thread:make-thread
(lambda () (sleep .01)))
353 (mapc #'sb-thread
:join-thread threads
)))
354 (unschedule-timer timer
))))
356 (test sb-thread
:*current-thread
*)))
358 ;; A timer with a repeat interval can be configured to "catch up" in
359 ;; case of missed calls.
360 (with-test (:name
(:timer
:catch-up
))
361 (flet ((test (&rest args
)
362 (let ((timer (make-timer (lambda ()))))
363 (apply #'schedule-timer timer
.01 args
)
364 (unschedule-timer timer
))))
365 ;; :CATCH-UP does not make sense without :REPEAT-INTERVAL.
366 (assert-error (test :catch-up nil
))
367 (assert-error (test :catch-up t
))
368 ;; These combinations are allowed.
369 (test :repeat-interval
.01 :catch-up nil
)
370 (test :repeat-interval
.01 :catch-up t
)))