[gambit-list] Pushing events between C++ and Scheme + timers

Marc Feeley feeley at IRO.UMontreal.CA
Wed Dec 8 15:37:00 EST 2004


> > Marc Feeley wrote:
> >Are you willing to start a C thread for the Scheme code? 
> 
> I could but I'd rather avoid it if I can.

That is a problem because the timers will only expire on time if C
returns control to Scheme in a timely manner.  Polling should be
avoided...  A possible solution is for the Scheme world to tell the C
world when its next scheduled timeout will be (i.e. the first
suspended thread on the Scheme thread scheduler's timeout queue), and
C has to call back to Scheme at that point at the lattest (so you have
to manage one timer on the C side for this).  There's currently no way
to tell when the next scheduled timeout will be, but a Scheme function
for this can easily be added to _thread.scm (5 lines of code).

> >This would
> >decouple control between Scheme and C, allowing timers to be
> >implemented in Scheme with the I/O timeout mechanisms.  
> 
> How would you implement these timers?

Here's some sample code:

(define-type timer
  mutex
)

(define (timer-start timeout thunk)
  (let* ((m (make-mutex))
         (t (make-timer m)))
    (mutex-lock! m) ; make sure mutex is locked
    (thread-start!
     (make-thread
      (lambda ()
        (if (mutex-lock! m timeout) ; block at most until timeout
            #f ; timer was stopped before the timeout
            (thunk)))))
    t))

(define (timer-stop timer)
  (mutex-unlock! (timer-mutex timer)))

(define t (timer-start 5 (lambda () (pp 'hello))))

;(timer-stop t)  ; uncomment to stop timer prematurely

(let loop () (thread-sleep! 1) (pp '*) (loop))

Alternatively, you could put the timeout on some blocking I/O
operation or synchronization operation (mutex, condition variable,
thread join, etc) and get the equivalent of a timer.

> >Then you need
> >two pipes between the C and Scheme worlds.  These pipes could be
> >actual OS pipes, sockets, or a new type of device (this would be more
> >efficient and portable, but require the implementation of a new device
> >in _os_io.c).
> 
> Can they be simple Scheme lists?
> 
> I thought I could have 3 Scheme functions I would call from C++ where one
> would start the Scheme loop in a Scheme thread and the other two would
> let C++ post events (sexp) to the "incoming events" Scheme list and the
> other would retrieve them from the "outgoing" list. The post/retrieve
> functions would use a mutex to block access to the lists/queues. Then I
> could do the timer by launching another thread within Gambit.
> 
> Maybe I'm misunderstanding the nature of integration that would be
> required here. Please let me know!

It can't just be a Scheme list.  You need some synchronization
mechanism.  Ideally the Scheme side should just try to get an event and
block until an event is available.  A FIFO created with open-vector-pipe
like this would do:

(receive (in out) (open-vector-pipe '(direction: input))
  ; in is the input port side of the FIFO and out is the
  ; output port side of the FIFO
  (write 111 out) ; first event
  (write 222 out) ; second event
  (write 333 out) ; third event
  (force-output out)
  (list (read in) (read in))) ; returns (111 222)

So the C side should call a Scheme function to add an event to
the FIFO (on the output port side), and this will unblock the
Scheme thread that is blocked on a read on the input port side
of the FIFO.

Marc


More information about the Gambit-list mailing list