gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gcl-devel] Re: with-timeout - a sketch?


From: Camm Maguire
Subject: [Gcl-devel] Re: with-timeout - a sketch?
Date: 01 Nov 2005 11:23:00 -0500
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

Greetings!

This stuff is quite interesting and ingenious!  Just thought I'd
mention a few things -- select in libc does something similar, and as
I've mentioned in the previous post we have a beginning hook now into
lisp.  CMUCL uses this for job multiplexing to my limited
understanding -- I believe all within one process.  select likely uses
some signalling mechanism internal to its definition, though I have no
knowledge of the particulars.  The older way to do i/o multiplexing
was by sending SIGIO.  In this case, one must take care that certain
system calls remain restartable across a signal.  On an earlier
project, I found out that one such call which could permanently fail
across signals regardless of file descriptor settings was read!
Finally, gcl-tk uses SIGUSR1 to communicate with gcltksrv, and the
windows port kills itself with sigalrm (apparently).  I like signals
in general, but there are certain portability problems, as well as
code protection issues.  You will see BEGIN_NO_INTERRUPT
etc. throughout the C code -- this blocks interfering signals during
the critical moments.  I've avoided building atop this structure, as I
have not verified for myself precisely what the minimal set of calls
needing protection is.  This aspect of GCL could use an overhaul.

Take care,


Robert Boyer <address@hidden> writes:

> ; Here is a sketch of an implementation of with-timeout.  It would be
> ; better if GCL had a function like get-universal-time that worked in
> ; microseconds and Linux had a sleep command that worked in
> ; microseconds.
> 
> ; We steal signal 2 so that it is no longer useful for GCL user
> ; interrupts to the console.  We should use some other signal number
> ; but don't know how.
> 
> ; The *waiting-stack* is a list of (i . time) pairs, where the i is an
> ; integer catch tag and time is a universal time.  In a good
> ; implementation, the tags would somehow have to be eq different from
> ; any tags the user might create, but we use simple integers here.
> (defvar *waiting-stack* nil)
> 
> ; *setting-up-timeout* is just a hack to indicate where a critical
> ; section is needed, but we'll never understand these things.
> (defvar *setting-up-timeout* nil)
> 
> (defmacro with-timeout (seconds &rest forms)
>   ;; If seconds pass before the evaluation of forms is complete, nil is 
> returned.
>   ;; Otherwise, the value of the last of forms is returned.
>   (let ((v (gensym)))
>     `(let* ((,v ,seconds)
>           (n (cond ((null *waiting-stack*) 0)
>                    (t (+ 1 (caar *waiting-stack*)))))
>           (w (cons (cons n (+ (get-universal-time) ,v))
>                    *waiting-stack*)))
>        (cond ((or *trying-to-stop* *setting-up-timeout*)
>             (error "Think harder!")))
>        (let* ((*setting-up-timeout* t)
>             (*waiting-stack* w))
>        ;; For an instant, *waiting-stack* has an entry on it that we better 
> not go to.
>        (catch n
>          (let ((*setting-up-timeout* nil))
>            ;; but now, the catch stack and *waiting-stack* are resynchronized.
>            (si::system (format nil "interrupt ~a ~a &" ,v (si::getpid)))
>            ,@forms))))))
>   
> ; *trying-to-stop* is just a hack to indicate where a critical section
> ; is needed, but we'll never understand these things.
> (defvar *trying-to-stop* nil)
> 
> (defun si::terminal-interrupt (correctablep)
>   (declare (ignore correctablep))
>   (cond ((or *trying-to-stop* *setting-up-timeout*)
>        (error "Think harder!")))
>   (let ((*trying-to-stop* t))
>     (let ((time (get-universal-time))
>         (destination nil))
>       (loop for x in *waiting-stack*
>           when (>= time (cdr x))
>           do (setq destination (car x)))
>       (cond (destination
>            (throw destination 'nil))))))
> 
> #|  Here is the file /u/boyer/bin/interrupt
> 
> sleep $1
> /bin/kill -2 $2
> 
> |#
> 
> ; Under this design, the user might create timer interrupts that may
> ; stay around for a long time after they are relevant to any body.  So
> ; perhaps a list of the process id's of timer interrupt processes
> ; created should be kept and occasionally cleansed by the top-level
> ; loop.
> 
> -------------------------------------------------------------------------------
> 
> 
> % g
> GCL (GNU Common Lisp)  2.7.0 ANSI    Oct 29 2005 16:46:15
> Source License: LGPL(gcl,gmp), GPL(unexec,bfd)
> Binary License:  GPL due to GPL'ed components: (BFD UNEXEC)
> Modifications of this banner must retain notice of a compatible license
> Dedicated to the memory of W. Schelter
> 
> Use (help) to get some basic information on how to use GCL.
> 
> >(load "foo.lisp")
> 
> Loading foo.lisp
> Finished loading foo.lisp
> T
> 
> >(time (with-timeout 1 (with-timeout 4 (with-timeout 300 (loop)))))
> 
> real time       :      1.040 secs
> run-gbc time    :      0.810 secs
> child run time  :      0.010 secs
> gbc time        :      0.200 secs
> NIL
> 
> >(time (with-timeout 8 (with-timeout 4 (with-timeout 300 (loop)))))
> 
> real time       :      4.030 secs
> run-gbc time    :      3.560 secs
> child run time  :      0.000 secs
> gbc time        :      0.440 secs
> NIL
> 
> >(time (with-timeout 8 (with-timeout 4 (with-timeout 1 'win))))
> 
> real time       :      0.010 secs
> run-gbc time    :      0.000 secs
> child run time  :      0.010 secs
> gbc time        :      0.000 secs
> WIN
> 
> >
> 
> 
> 

-- 
Camm Maguire                                            address@hidden
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah




reply via email to

[Prev in Thread] Current Thread [Next in Thread]