[racket] scheme_call_enable_break

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sun Apr 21 13:05:01 EDT 2013

At Sun, 21 Apr 2013 18:30:44 +0200, Laurent wrote:
> Is it possible to use scheme_call_enable_break [1] with a non-primitive
> Racket procedure?

No. That C function is merely

 (define (call/enable-break f)
   (parameterize-break #t (f)))

but in a more convenient form to call from C.

More generally, scheme_call_enable_break() works with a kind of C
function that is implicitly atomic except when explicitly yielding, and
that model doesn't really fit with Racket functions (including ones
that use the FFI).


> In particular, I'd like to use it with shawnpresser's unix domain socket
> package [2] and its `accept' function, but I'm not sure how to make one
> work with the other.

If I'm reading that code correctly, the implementation of `accept' uses
accept() in a way that's going to block the Racket process (unless the
given socket is configured as non-blocking).

If a break is delivered to the process via Ctl-C or otherwise as an OS
signal, accept() will return with EINTR, but that's independent of
whether Racket breaks are allowed for the thread.


I think you want to use scheme_fd_to_semaphore() [oops, not documented
--- I'll fix that] to get a synchronizable event. Then, you can wait
until a connection is ready; then, in atomic mode, double-check that a
connection is still ready and accept it. Enable breaks while waiting on
the semaphore iff breaks where enabled on entry, but otherwise disable
breaks.

Something like this (untested):

 (define MZFD_CHECK_READ 3)
 (define scheme_fd_to_semaphore
   (get-ffi-obj 'scheme_fd_to_semaphore#f
                (_fun _intptr _int _bool -> _racket)))

 (define (nice-accept fd break-ok?)
   (parameterize-break
    #f
    (lambda ()
      (let loop ()
        ;; wait, with breaks possibly enabled:
        (parameterize-break
         break-ok?
         (lambda () (sync (scheme_fd_to_semaphore fd MZFD_CHECK_READ #t))))
        ((call-as-atomic
          (lambda ()
           ;; in atomic mode to avoid a race between the accept test and
           ;; actually accepting; works as long as no other OS thread
           ;; or process accepts from the same socket. It may be better
           ;; to put the socket in non-blocking mode and handle EWOULDBLOCK,
           ;; instead.
           (if ....connection-ready? on s ...
               ;; Ready, accept it:
               (let ([v (accept s)]) (lambda () v))
               ;; not ready, try again:
               loop))))))))


Posted on the users mailing list.