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