(module timer mzscheme (require "timer-structs.ss") (require (lib "list.ss") (lib "async-channel.ss")) (provide timer? start-timer reset-timer! increment-timer! cancel-timer! start-timer-manager) (define timer-ch (make-async-channel)) ; start-timer-manager : custodian -> void ; The timer manager thread (define (start-timer-manager server-custodian) (parameterize ([current-custodian server-custodian]) (thread (lambda () (let loop ([timers null]) ;; Wait for either... (apply sync ;; ... a timer-request message ... (handle-evt timer-ch (lambda (req) ;; represent a req as a (timer-list -> timer-list) function: ;; add/remove/change timer evet: (loop (req timers)))) ;; ... or a timer (map (lambda (timer) (handle-evt (timer-evt timer) (lambda (_) ;; execute timer ((timer-action timer)) (loop (remq timer timers))))) timers)))))) (void)) ;; Limitation on this add-timer: thunk cannot make timer ;; requests directly, because it's executed directly by ;; the timer-manager thread ;; add-timer : number (-> void) -> timer (define (add-timer msecs thunk) (let* ([now (current-inexact-milliseconds)] [timer (make-timer (alarm-evt (+ now msecs)) (+ now msecs) thunk)]) (async-channel-put timer-ch (lambda (timers) (cons timer timers))) timer)) ; revise-timer! : timer msecs (-> void) -> timer ; revise the timer to ring msecs from now (define (revise-timer! timer msecs thunk) (let ([now (current-inexact-milliseconds)]) (async-channel-put timer-ch (lambda (timers) (set-timer-evt! timer (alarm-evt (+ now msecs))) (set-timer-expire-seconds! timer (+ now msecs)) (set-timer-action! timer thunk) timers)))) (define (cancel-timer! timer) (revise-timer! timer 0 void)) ; start-timer : num (-> void) -> timer ; to make a timer that calls to-do after sec from make-timer's application (define (start-timer secs to-do) (add-timer (* 1000 secs) to-do)) ; reset-timer : timer num -> void ; to cause timer to expire after sec from the adjust-msec-to-live's application (define (reset-timer! timer secs) (revise-timer! timer (* 1000 secs) (timer-action timer))) ; increment-timer! : timer num -> void ; add secs to the timer, rather than replace (define (increment-timer! timer secs) (revise-timer! timer (+ (- (timer-expire-seconds timer) (current-inexact-milliseconds)) (* 1000 secs)) (timer-action timer)))) ; --- timeout plan ; start timeout on connection startup ; for POST requests increase the timeout proportionally when content-length is read ; adjust timeout in read-to-eof ; adjust timeout to starting timeout for next request with persistent connections ; adjust timeout proportionally when responding ; for servlet - make it a day until the output is produced