Rewrite of timeout manager and fixing of connection mutex bug on kill
svn: r684
This commit is contained in:
parent
0309108a41
commit
7ada980df0
|
@ -21,7 +21,7 @@
|
|||
(collect-garbage
|
||||
"collect-garbage.html"))
|
||||
(timeouts
|
||||
(default-servlet-timeout 120)
|
||||
(default-servlet-timeout 30)
|
||||
(password-connection-timeout 300)
|
||||
(servlet-connection-timeout 86400)
|
||||
(file-per-byte-connection-timeout 1/20)
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
[adjust-connection-timeout! (connection? number? . -> . void)])
|
||||
|
||||
;; start-connection-manager: custodian -> void
|
||||
;; does nothing
|
||||
(define start-connection-manager void)
|
||||
;; calls the timer manager
|
||||
(define (start-connection-manager custodian)
|
||||
(start-timer-manager custodian))
|
||||
|
||||
;; new-connection: number i-port o-port custodian -> connection
|
||||
;; ask the connection manager for a new connection
|
||||
|
@ -31,14 +32,11 @@
|
|||
|
||||
;; kill-connection!: connection -> void
|
||||
;; kill this connection
|
||||
(define (kill-connection! conn-demned)
|
||||
(call-with-semaphore
|
||||
(connection-mutex conn-demned)
|
||||
(lambda ()
|
||||
(close-output-port (connection-o-port conn-demned))
|
||||
(close-input-port (connection-i-port conn-demned))
|
||||
(set-connection-close?! conn-demned #t)
|
||||
(custodian-shutdown-all (connection-custodian conn-demned)))))
|
||||
(define (kill-connection! conn-demned)
|
||||
(close-output-port (connection-o-port conn-demned))
|
||||
(close-input-port (connection-i-port conn-demned))
|
||||
(set-connection-close?! conn-demned #t)
|
||||
(custodian-shutdown-all (connection-custodian conn-demned)))
|
||||
|
||||
;; adjust-connection-timeout!: connection number -> void
|
||||
;; change the expiration time for this connection
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
(make-execution-context
|
||||
conn req (lambda () (suspend #t)))
|
||||
sema
|
||||
(start-timer 0 (lambda () (void))))]
|
||||
(start-timer 0 void))]
|
||||
[real-servlet-path (url-path->path
|
||||
(paths-servlet (host-paths host-info))
|
||||
(url-path->string (url-path uri)))]
|
||||
|
@ -326,7 +326,7 @@
|
|||
|
||||
|
||||
(define servlet-bin?
|
||||
(let ([svt-bin-re (regexp "^/servlets/.*")])
|
||||
(let ([svt-bin-re (regexp "^/servlets(;id.*\\*.*\\*.*)?/.*")])
|
||||
(lambda (str)
|
||||
(regexp-match svt-bin-re str))))
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
(module timer-structs mzscheme
|
||||
(require (lib "contract.ss"))
|
||||
|
||||
(define-struct timer (expire-seconds))
|
||||
(define-struct timer (evt expire-seconds action))
|
||||
(provide/contract
|
||||
[struct timer ([expire-seconds number?])]))
|
||||
[struct timer ([evt evt?]
|
||||
[expire-seconds number?]
|
||||
[action (-> void)])]))
|
|
@ -1,37 +1,87 @@
|
|||
(module timer mzscheme
|
||||
(require "timer-structs.ss")
|
||||
(provide timer? start-timer reset-timer increment-timer)
|
||||
(require (lib "list.ss"))
|
||||
(provide timer?
|
||||
start-timer reset-timer increment-timer
|
||||
start-timer-manager)
|
||||
|
||||
; BUG: reducing the timeout is ineffective
|
||||
; efficiency: too many threads
|
||||
(define timer-ch (make-channel))
|
||||
|
||||
; start-timer-manager : custodian -> void
|
||||
; Thanks to Matthew!
|
||||
; 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)])
|
||||
(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)])
|
||||
(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 msec from make-timer's application
|
||||
(define (start-timer sec to-do)
|
||||
(let ([timer (make-timer (+ (current-seconds) sec))])
|
||||
(letrec ([snooze
|
||||
(lambda ()
|
||||
(let ([remaining (- (timer-expire-seconds timer) (current-seconds))])
|
||||
(cond
|
||||
[(<= remaining 0)
|
||||
; use call-in-nested-thread or something when a single thread is used for all timeouts
|
||||
(to-do)]
|
||||
[else (sleep remaining)
|
||||
(snooze)])))])
|
||||
(thread snooze))
|
||||
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 sec)
|
||||
(set-timer-expire-seconds! timer (+ sec (current-seconds))))
|
||||
(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 sec)
|
||||
(set-timer-expire-seconds! timer (+ sec (timer-expire-seconds timer)))))
|
||||
|
||||
|
||||
(define (increment-timer timer secs)
|
||||
(revise-timer! timer
|
||||
(+ (timer-expire-seconds timer)
|
||||
(* 1000 secs))
|
||||
(timer-action timer))))
|
||||
|
||||
; --- timeout plan
|
||||
|
||||
|
|
|
@ -97,11 +97,10 @@
|
|||
;; serve-ports : input-port output-port -> void
|
||||
;; returns immediately, spawning a thread to handle
|
||||
;; the connection
|
||||
;; NOTE: this doesn't use a connection manager since
|
||||
;; connection managers don't do anything anyways. -robby
|
||||
;; NOTE: (GregP) should allow the user to pass in a connection-custodian
|
||||
(define (serve-ports ip op)
|
||||
(let ([server-cust (make-custodian)])
|
||||
(start-connection-manager server-cust)
|
||||
(parameterize ([current-custodian server-cust]
|
||||
[current-server-custodian server-cust])
|
||||
(let ([connection-cust (make-custodian)])
|
||||
|
@ -118,7 +117,6 @@
|
|||
(with-handlers ([exn:fail:network?
|
||||
(lambda (e)
|
||||
(set-connection-close?! conn #t)
|
||||
; XXX: Can this block on the mutex?
|
||||
(kill-connection! conn)
|
||||
(raise e))])
|
||||
(serve-connection conn))))))
|
||||
|
|
Loading…
Reference in New Issue
Block a user