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 ,@timeout-body)))))) (sb-ext:schedule-timer ,timer-sym ,seconds) (unwind-protect (progn ,@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.l...@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 () > ,@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 _______________________________________________ drakma-devel mailing list drakma-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/drakma-devel