1.0.26.4: less pessimal waitqueues
[sbcl.git] / tests / timer.impure.lisp
index 29d2fbd..3f16fa1 100644 (file)
 
 (use-package :test-util)
 
+(sb-alien:define-alien-routine "check_deferrables_blocked_or_lose"
+    void)
+(sb-alien:define-alien-routine "check_deferrables_unblocked_or_lose"
+    void)
+
+(defun make-limited-timer (fn n &rest args)
+  (let (timer)
+    (setq timer
+          (apply #'sb-ext:make-timer
+                 (lambda ()
+                   (sb-sys:without-interrupts
+                     (decf n)
+                     (cond ((minusp n)
+                            (warn "Unscheduling timer ~A ~
+                                   upon reaching run limit. System too slow?"
+                                  timer)
+                            (sb-ext:unschedule-timer timer))
+                           (t
+                            (sb-sys:allow-with-interrupts
+                              (funcall fn))))))
+                 args))))
+
+(defun make-and-schedule-and-wait (fn time)
+  (let ((finishedp nil))
+    (sb-ext:schedule-timer (sb-ext:make-timer
+                            (lambda ()
+                              (sb-sys:without-interrupts
+                                (unwind-protect
+                                     (sb-sys:allow-with-interrupts
+                                       (funcall fn))
+                                  (setq finishedp t)))))
+                           time)
+    (loop until finishedp)))
+
+(with-test (:name (:timer :deferrables-blocked))
+  (make-and-schedule-and-wait (lambda ()
+                                (check-deferrables-blocked-or-lose))
+                              (random 0.1))
+  (check-deferrables-unblocked-or-lose))
+
+(with-test (:name (:timer :deferrables-unblocked))
+  (make-and-schedule-and-wait (lambda ()
+                                (sb-sys:with-interrupts
+                                  (check-deferrables-unblocked-or-lose)))
+                              (random 0.1))
+  (check-deferrables-unblocked-or-lose))
+
+#-win32
+(with-test (:name (:timer :deferrables-unblocked :unwind))
+  (catch 'xxx
+    (make-and-schedule-and-wait (lambda ()
+                                  (check-deferrables-blocked-or-lose)
+                                  (throw 'xxx nil))
+                                (random 0.1))
+    (sleep 1))
+  (check-deferrables-unblocked-or-lose))
+
 (defmacro raises-timeout-p (&body body)
   `(handler-case (progn (progn ,@body) nil)
     (sb-ext:timeout () t)))
         (loop
            (assert (eq wanted (subtypep type1 type2))))))))
 
+;;; Used to hang occasionally at least on x86. Two bugs caused it:
+;;; running out of stack (due to repeating timers being rescheduled
+;;; before they ran) and dying threads were open interrupts.
 #+sb-thread
 (with-test (:name (:timer :parallel-unschedule))
   (let ((timer (sb-ext:make-timer (lambda () 42) :name "parallel schedulers"))
                        (loop for i from 1 upto 10
                              collect (let* ((thread (sb-thread:make-thread #'flop
                                                                            :name (format nil "scheduler ~A" i)))
-                                            (ticker (sb-ext:make-timer (lambda () 13) :thread (or other thread)
-                                                                       :name (format nil "ticker ~A" i))))
+                                            (ticker (make-limited-timer (lambda () 13)
+                                                                               1000
+                                                                               :thread (or other thread)
+                                                                               :name (format nil "ticker ~A" i))))
                                        (setf other thread)
                                        (sb-ext:schedule-timer ticker 0 :repeat-interval 0.00001)
                                        thread)))))))
 
-;;;; OS X doesn't like these being at all, and gives us a SIGSEGV
-;;;; instead of using the Mach expection system! Our or OS X's fault?
-;;;; :/
-
+;;;; FIXME: OS X 10.4 doesn't like these being at all, and gives us a SIGSEGV
+;;;; instead of using the Mach expection system! 10.5 on the other tends to
+;;;; lose() here with interrupt already pending. :/
+;;;;
+;;;; Used to have problems in genereal, see comment on (:TIMER
+;;;; :PARALLEL-UNSCHEDULE).
 (with-test (:name (:timer :schedule-stress))
   (flet ((test ()
-           (let* ((slow-timers (loop for i from 1 upto 100
-                                     collect (sb-ext:make-timer (lambda () 13) :name (format nil "slow ~A" i))))
-                  (fast-timer (sb-ext:make-timer (lambda () 42) :name "fast")))
-             (sb-ext:schedule-timer fast-timer 0.0001 :repeat-interval 0.0001)
-             (dolist (timer slow-timers)
-               (sb-ext:schedule-timer timer (random 0.1) :repeat-interval (random 0.1)))
-             (dolist (timer slow-timers)
-               (sb-ext:unschedule-timer timer))
-             (sb-ext:unschedule-timer fast-timer))))
-    #+sb-thread
-    (mapcar #'sb-thread:join-thread (loop repeat 10 collect (sb-thread:make-thread #'test)))
-    #-sb-thread
-    (loop repeat 10 do (test))))
+         (let* ((slow-timers
+                 (loop for i from 1 upto 1
+                       collect (make-limited-timer
+                                (lambda () 13)
+                                1000
+                                :name (format nil "slow ~A" i))))
+                (fast-timer (make-limited-timer (lambda () 42) 1000
+                                                :name "fast")))
+           (sb-ext:schedule-timer fast-timer 0.0001 :repeat-interval 0.0001)
+           (dolist (timer slow-timers)
+             (sb-ext:schedule-timer timer (random 0.1)
+                                    :repeat-interval (random 0.1)))
+           (dolist (timer slow-timers)
+             (sb-ext:unschedule-timer timer))
+           (sb-ext:unschedule-timer fast-timer))))
+  #+sb-thread
+  (mapcar #'sb-thread:join-thread
+          (loop repeat 10 collect (sb-thread:make-thread #'test)))
+  #-sb-thread
+  (loop repeat 10 do (test))))
 
 #+sb-thread
 (with-test (:name (:timer :threaded-stress))
                                                 do (sb-ext:schedule-timer (make-timer #'one :thread thread) 0.001))))))
           (dolist (thread threads)
             (sched thread)))
-        (with-timeout (truncate goal 100)
-          (mapcar #'sb-thread:join-thread threads))))))
+        (mapcar #'sb-thread:join-thread threads)))))