[racket] scheme_call_enable_break
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))))))))