X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Ftimer.lisp;h=88b9c1da4315e5d1240b3381b44d897fead1ab88;hb=ba12c5c0420f28250ef4931b47af92c6d7963195;hp=065b4c22e6e6007733b14b4a7d5ad19eba787472;hpb=f9b0f51a03824319cb45388c5a9fdb813c04f2d1;p=sbcl.git diff --git a/src/code/timer.lisp b/src/code/timer.lisp index 065b4c2..88b9c1d 100644 --- a/src/code/timer.lisp +++ b/src/code/timer.lisp @@ -156,14 +156,15 @@ future versions." (defun make-timer (function &key name (thread sb!thread:*current-thread*)) #!+sb-doc - "Create a timer object that's when scheduled runs FUNCTION. If -THREAD is a thread then that thread is to be interrupted with -FUNCTION. If THREAD is T then a new thread is created each timer -FUNCTION is run. If THREAD is NIL then FUNCTION can be run in any -thread. When THREAD is not T, INTERRUPT-THREAD is used to run FUNCTION -and the ordering guarantees of INTERRUPT-THREAD also apply here. -FUNCTION always runs with interrupts disabled but WITH-INTERRUPTS is -allowed." + "Create a timer that runs FUNCTION when triggered. + +If a THREAD is supplied, FUNCTION is run in that thread. If THREAD is +T, a new thread is created for FUNCTION each time the timer is +triggered. If THREAD is NIL, FUNCTION is run in an unspecified thread. + +When THREAD is not T, INTERRUPT-THREAD is used to run FUNCTION and the +ordering guarantees of INTERRUPT-THREAD apply. FUNCTION runs with +interrupts disabled but WITH-INTERRUPTS is allowed." (%make-timer :name name :function function :thread thread)) (defun timer-name (timer) @@ -285,6 +286,8 @@ triggers." (setf (%timer-expire-time timer) nil (%timer-repeat-interval timer) nil) (let ((old-position (priority-queue-remove *schedule* timer))) + ;; Don't use cancel-function as the %timer-cancel-function + ;; may have changed before we got the scheduler lock. (when old-position (funcall (%timer-cancel-function timer))) (when (eql 0 old-position) @@ -355,23 +358,26 @@ triggers." (warn "Timer ~S failed to interrupt thread ~S." timer thread))))))) -;;; Called from the signal handler. +;;; Called from the signal handler. We loop until all the expired timers +;;; have been run. (defun run-expired-timers () - (let (timer) - (with-scheduler-lock () - (setq timer (peek-schedule)) - (when (or (null timer) - (< (get-internal-real-time) - (%timer-expire-time timer))) - ;; Seemingly this is a spurious SIGALRM, but play it safe and - ;; reset the system timer because if the system clock was set - ;; back after the SIGALRM had been delivered then we won't get - ;; another chance. - (set-system-timer) - (return-from run-expired-timers nil)) - (assert (eq timer (priority-queue-extract-maximum *schedule*))) - (set-system-timer)) - (run-timer timer))) + (loop + (let ((now (get-internal-real-time)) + (timers nil)) + (flet ((run-timers () + (dolist (timer (nreverse timers)) + (run-timer timer)))) + (with-scheduler-lock () + (loop for timer = (peek-schedule) + when (or (null timer) (< now (%timer-expire-time timer))) + ;; No more timers to run for now, reset the system timer. + do (run-timers) + (set-system-timer) + (return-from run-expired-timers nil) + else + do (assert (eq timer (priority-queue-extract-maximum *schedule*))) + (push timer timers))) + (run-timers))))) (defun timeout-cerror () (cerror "Continue" 'sb!ext::timeout))