[drakma-devel] [usocket-devel] [patch] Resubmit drakma timeout for sbcl.
Chun Tian (binghe)
binghe.lisp at gmail.com
Mon Mar 28 22:43:47 UTC 2011
I know SBCL's WITH-TIMEOUT cannot nest, I learn this from GBBopen's portable-threads.lisp [1], and it also give a nested version SBCL's WITH-TIMEOUT, much shorter than yours:
#+sbcl
(defmacro with-timeout ((seconds &body timeout-body) &body timed-body)
(let ((tag-sym (gensym))
(timer-sym (gensym)))
`(block ,tag-sym
(let ((,timer-sym
(sb-ext:make-timer
#'(lambda ()
(return-from ,tag-sym (progn , at timeout-body))))))
(sb-ext:schedule-timer ,timer-sym ,seconds)
(unwind-protect (progn , at timed-body)
(sb-ext:unschedule-timer ,timer-sym))))))
I didn't use this version simply because I think the WITH-TIMEOUT form in usocket's SOCKET-CONNECT has no chance to be nested.
--binghe
在 2011-3-29,04:35, Nikodemus Siivola 写道:
> 2011/3/28 Chun Tian (binghe) <binghe.lisp at gmail.com>:
>
>> Today I think out another way to solve the SBCL connection timeout issue, I wrap a
>> SB-EXT:WITH-TIMEOUT on SB-BSD-SOCKET:SOCKET-CONNNECT [1], and the result work seems working well:
>
> That's along the lines I was thinking off, except that
> SB-EXT:WITH-TIMEOUT is a broken construct. (Soon to be deprecated, in
> all likelihood.)
>
> Consider this:
>
> (with-timeout 1.0 (handler-case (with-timeout 4.0 (sleep 2))
> (sb-ext:timeout ())))
>
> which is to say that you cannot distinguish an outer timeout from an
> inner one, which is bad.
>
> You need something like this, instead:
>
> (defmacro with-timeout-handler ((seconds timeout-form) &body body)
> "Runs BODY as an implicit PROGN with timeout of SECONDS. If
> timeout occurs before BODY has finished, BODY is unwound and
> TIMEOUT-FORM is executed with its values returned instead.
>
> Note that BODY is unwound asynchronously when a timeout occurs,
> so unless all code executed during it -- including anything
> down the call chain -- is asynch unwind safe, bad things will
> happen. Use with care."
> (alexandria:with-gensyms (exec unwind timer timeout block)
> `(block ,block
> (tagbody
> (flet ((,unwind ()
> (go ,timeout))
> (,exec ()
> , at body))
> (declare (dynamic-extent #',exec #',unwind))
> (let ((,timer (sb-ext:make-timer #',unwind)))
> (declare (dynamic-extent ,timer))
> (sb-sys:without-interrupts
> (unwind-protect
> (progn
> (sb-ext:schedule-timer ,timer ,seconds)
> (return-from ,block
> (sb-sys:with-local-interrupts
> (,exec))))
> (sb-ext:unschedule-timer ,timer)))))
> ,timeout
> (return-from ,block ,timeout-form)))))
>
> with which
>
> (with-timeout-handler (1.0 :outer) (with-timeout-handler (4.0
> :inner) (sleep 10.0) :ok))
>
> does the right thing.
>
> Gods, I hate asynch timeouts. Is there a sane way to tell connect() to
> time out without needing SIGALRM?
>
> Cheers,
>
> -- Nikodemus
More information about the Drakma-devel
mailing list