[drakma-devel] [usocket-devel] [patch] Resubmit drakma timeout for sbcl.

Nikodemus Siivola nikodemus at random-state.net
Mon Mar 28 20:35:14 UTC 2011


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