Puzzle... what's the bug in the following code? See end of message for answer.
(define http-server-start! (lambda (hs stop?) (let ((server-port (open-tcp-server (list port-number: (server-port-number hs) backlog: 128 reuse-address: #t server-address: '#u8(127 0 0 1) ; on localhost interface only char-encoding: 'ISO-8859-1)))) (input-port-timeout-set! server-port 3) (accept-connections hs server-port stop?))))
(define accept-connections (lambda (hs server-port stop?) (let loop () (let ((connection (read server-port))) (if (eof-object? connection) (if (stop?) (close-input-port server-port) (loop)) (begin (if (server-threaded? hs) (let ((dummy-port (open-dummy))) (parameterize ((current-input-port dummy-port) (current-output-port dummy-port)) (thread-start! (make-thread (lambda () (serve-connection hs connection)))))) (serve-connection hs connection)) (loop)))))))
. . . . . . . .
Answer: the (input-port-timeout-set! server-port 3) is at the wrong place. It sets a timeout ***3 seconds in the future***. So after 3 seconds have passed all calls to read in accept-connections will not block (and lead to a tight, CPU intensive loop). The correct approach is to put the call to (input-port-timeout-set! server-port 3) just before the call to read.
Puzzle #2: why did Gambit chose to define timeouts that are not relative to the moment that an I/O function is called?
Marc
Afficher les réponses par date
Hallo,
On Thu, Oct 30, 2008 at 6:18 PM, Marc Feeleyfeeley@iro.umontreal.ca wrote:
Puzzle... what's the bug in the following code? See end of message for answer.
(define http-server-start! (lambda (hs stop?) (let ((server-port (open-tcp-server (list port-number: (server-port-number hs) backlog: 128 reuse-address: #t server-address: '#u8(127 0 0 1) ; on localhost interface only char-encoding: 'ISO-8859-1)))) (input-port-timeout-set! server-port 3) (accept-connections hs server-port stop?))))
(define accept-connections (lambda (hs server-port stop?) (let loop () (let ((connection (read server-port))) (if (eof-object? connection) (if (stop?) (close-input-port server-port) (loop)) (begin (if (server-threaded? hs) (let ((dummy-port (open-dummy))) (parameterize ((current-input-port dummy-port) (current-output-port dummy-port)) (thread-start! (make-thread (lambda () (serve-connection hs connection)))))) (serve-connection hs connection)) (loop)))))))
. . . . . . . .
Answer: the (input-port-timeout-set! server-port 3) is at the wrong place. It sets a timeout ***3 seconds in the future***. So after 3 seconds have passed all calls to read in accept-connections will not block (and lead to a tight, CPU intensive loop). The correct approach is to put the call to (input-port-timeout-set! server-port 3) just before the call to read.
Puzzle #2: why did Gambit chose to define timeouts that are not relative to the moment that an I/O function is called?
I know this is ancient, but I missed the question when I first received the email. Well, why? :)
Cheers,
On 9-Jun-09, at 10:24 PM, Alex Queiroz wrote:
Puzzle #2: why did Gambit chose to define timeouts that are not relative to the moment that an I/O function is called?
I know this is ancient, but I missed the question when I first received the email. Well, why? :)
Because it does not work in the presence of abstraction. Let's suppose that timeouts were relative to when the primitive is called and that the timeout is 3 seconds. Then how would you write read-line so that the timeout will work consistently (that is, it will timeout 3 seconds after the call to read-line)?
read-line cannot be written like this:
(define (read-line port) (let loop (...) ... (read-char port) ... (loop ...)))
because for each call to read-char a timeout of 3 seconds relative to that particular call to read-char will happen. So, read-line will keep reading characters as long as the time between reading each char is less than 3 seconds. So read-line can execute for arbitrarily long... it does not timeout 3 seconds after it is called.
Absolute timeouts eliminate this issue.
Marc
Hallo,
On Wed, Jun 10, 2009 at 12:10 AM, Marc Feeleyfeeley@iro.umontreal.ca wrote:
because for each call to read-char a timeout of 3 seconds relative to that particular call to read-char will happen. So, read-line will keep reading characters as long as the time between reading each char is less than 3 seconds. So read-line can execute for arbitrarily long... it does not timeout 3 seconds after it is called.
Absolute timeouts eliminate this issue.
Thanks for the explanation.
Cheers,