Hi Gary,
I've modified with-timeout.lisp to add LispWorks support. I've "tested" it (where "tested" == "debugged"). I have attached a unified diff and my modified source file.
It seemed to me that your uses of PROGN and VALUES were redundant, and I'm curious as to why they were present (and/or whether I'm just wrong).
I hope this is useful. I'd be interested in any comments or feedback you might have.
Cheers,
John :^P -- John Pallister john@synchromesh.com
--- with-timeout-orig.lisp 2008-09-11 01:46:15.000000000 +1200 +++ with-timeout.lisp 2008-09-12 15:49:25.140625000 +1200 @@ -21,22 +21,23 @@ If `seconds` is nil, then the body will be run normally until it completes or is interrupted." (let ((gseconds (gensym "seconds-")) + (gdoit (gensym "doit-")) #+(and sbcl (not sb-thread)) (glabel (gensym "label-")) #+(and sbcl (not sb-thread)) (gused-timer? (gensym "used-timer-"))) `(let ((,gseconds ,seconds)) - (flet ((doit () - (progn ,@body))) - (cond (,gseconds + (flet ((,gdoit () + ,@body)) + (cond ((and (numberp ,gseconds) (> ,gseconds 0)) #+allegro (mp:with-timeout (,gseconds (error 'timeout-error)) - (doit)) + (,gdoit)) #+cmu - (mp:with-timeout (,gseconds) (doit)) + (mp:with-timeout (,gseconds) (,gdoit)) #+(and sbcl sb-thread) (handler-case - (sb-ext:with-timeout ,gseconds (doit)) + (sb-ext:with-timeout ,gseconds (,gdoit)) (sb-ext::timeout (c) (error 'timeout-error))) #+(and sbcl (not sb-thread)) @@ -47,7 +48,7 @@ (setf ,gused-timer? t) (throw ',glabel nil))) ,gseconds) - (doit)) + (,gdoit)) (when ,gused-timer? (error 'timeout-error))) #+(or digitool openmcl ccl) @@ -59,7 +60,7 @@ (,process (ccl:process-run-function ,checker-process (lambda () - (setf ,result (progn (doit))))))) + (setf ,result (,gdoit)))))) (ccl:process-wait-with-timeout ,waiting-process (* ,gseconds #+(or openmcl ccl) @@ -69,8 +70,23 @@ (when (ccl::process-active-p ,process) (ccl:process-kill ,process) (cerror "Timeout" 'timeout-error)) - (values ,result))) - #-(or allegro cmu sbcl openmcl ccl mcl digitool) - (progn (doit))) + ,result)) + #+lispworks + ,(let ((gresult (gensym "result-")) + (gprocess (gensym "process-"))) + `(let* (,gresult + (,gprocess (mp:process-run-function "WITH-TIMEOUT" + '() + (lambda () + (setq ,gresult (,gdoit)))))) + (unless (mp:process-wait-with-timeout "WITH-TIMEOUT" + ,gseconds + (lambda () + (not (mp:process-alive-p ,gprocess)))) + (mp:process-kill ,gprocess) + (cerror "Timeout" 'timeout-error)) + ,gresult)) + #-(or allegro cmu sbcl openmcl ccl mcl digitool lispworks) + (,gdoit)) (t - (doit))))))))) + (,gdoit)))))))))
(in-package #:com.metabang.trivial-timeout)
(eval-when (:compile-toplevel :load-toplevel :execute) (unless (and (find-symbol (symbol-name '#:with-timeout) '#:com.metabang.trivial-timeout) (fboundp (find-symbol (symbol-name '#:with-timeout) '#:com.metabang.trivial-timeout))) (define-condition timeout-error (error) () (:report (lambda (c s) (declare (ignore c)) (format s "Process timeout"))) (:documentation "An error signaled when the duration specified in the [with-timeout][] is exceeded."))
(defmacro with-timeout ((seconds) &body body) "Execute `body` for no more than `seconds` time.
If `seconds` is exceeded, then a [timeout-error][] will be signaled.
If `seconds` is nil, then the body will be run normally until it completes or is interrupted." (let ((gseconds (gensym "seconds-")) (gdoit (gensym "doit-")) #+(and sbcl (not sb-thread)) (glabel (gensym "label-")) #+(and sbcl (not sb-thread)) (gused-timer? (gensym "used-timer-"))) `(let ((,gseconds ,seconds)) (flet ((,gdoit () ,@body)) (cond ((and (numberp ,gseconds) (> ,gseconds 0)) #+allegro (mp:with-timeout (,gseconds (error 'timeout-error)) (,gdoit)) #+cmu (mp:with-timeout (,gseconds) (,gdoit)) #+(and sbcl sb-thread) (handler-case (sb-ext:with-timeout ,gseconds (,gdoit)) (sb-ext::timeout (c) (error 'timeout-error))) #+(and sbcl (not sb-thread)) (let ((,gused-timer? nil)) (catch ',glabel (sb-ext:schedule-timer (sb-ext:make-timer (lambda () (setf ,gused-timer? t) (throw ',glabel nil))) ,gseconds) (,gdoit)) (when ,gused-timer? (error 'timeout-error))) #+(or digitool openmcl ccl) ,(let ((checker-process (format nil "Checker ~S" (gensym))) (waiting-process (format nil "Waiter ~S" (gensym))) (result (gensym)) (process (gensym))) `(let* ((,result nil) (,process (ccl:process-run-function ,checker-process (lambda () (setf ,result (,gdoit)))))) (ccl:process-wait-with-timeout ,waiting-process (* ,gseconds #+(or openmcl ccl) ccl:*ticks-per-second* #+digitool 60) (lambda () (not (ccl::process-active-p ,process)))) (when (ccl::process-active-p ,process) (ccl:process-kill ,process) (cerror "Timeout" 'timeout-error)) ,result)) #+lispworks ,(let ((gresult (gensym "result-")) (gprocess (gensym "process-"))) `(let* (,gresult (,gprocess (mp:process-run-function "WITH-TIMEOUT" '() (lambda () (setq ,gresult (,gdoit)))))) (unless (mp:process-wait-with-timeout "WITH-TIMEOUT" ,gseconds (lambda () (not (mp:process-alive-p ,gprocess)))) (mp:process-kill ,gprocess) (cerror "Timeout" 'timeout-error)) ,gresult)) #-(or allegro cmu sbcl openmcl ccl mcl digitool lispworks) (,gdoit)) (t (,gdoit)))))))))
Hi John,
Thanks very much for this contribution to trivial-timeout. You're absolutely right that doit needs to be protected with a gensym. Good catch for my miss!
As for the progn and the values... go figure. I originally wrote this code a _long_ time ago and I was probably being, I don't know, overprotective. They certainly look redundant now.
I've rearranged the code in a way that I think makes multiple platform support easier to implement and understand; I'll be posting version 0.1.3 later today.
On Sep 12, 2008, at 12:13 AM, John Pallister wrote:
Hi Gary,
I've modified with-timeout.lisp to add LispWorks support. I've "tested" it (where "tested" == "debugged"). I have attached a unified diff and my modified source file.
It seemed to me that your uses of PROGN and VALUES were redundant, and I'm curious as to why they were present (and/or whether I'm just wrong).
I hope this is useful. I'd be interested in any comments or feedback you might have.
Cheers,
-- Gary Warren King, metabang.com Cell: (413) 559 8738 Fax: (206) 338-4052 gwkkwg on Skype * garethsan on AIM
trivial-timeout-devel@common-lisp.net