fix unsafe-poller result handling and improve docs

This commit is contained in:
Matthew Flatt 2017-12-12 12:07:41 -07:00
parent 544b7a3d53
commit 5ad28e8942
4 changed files with 75 additions and 17 deletions

View File

@ -6,7 +6,9 @@
@defmodule[ffi/unsafe/schedule]{The
@racketmodname[ffi/unsafe/schedule] library provides functions for
cooperating with the thread scheduler and manipulating it.}
cooperating with the thread scheduler and manipulating it. These
operations are unsafe because callbacks run in @tech{atomic mode}
and in an unspecified thread.}
@history[#:added "6.11.0.1"]
@ -16,8 +18,8 @@ cooperating with the thread scheduler and manipulating it.}
Produces a @deftech{poller} value that is allowed as a
@racket[prop:evt] value, even though it is not a procedure or itself
an @racket[evt?]. The @racket[poll] callback is called in @tech{atomic
mode} to check whether the event is ready or to allow it to register a
wakeup trigger.
mode} in an unspecified thread to check whether the event is ready or
to allow it to register a wakeup trigger.
The first argument to @racket[poll] is always the object that is used
as a @tech[#:doc reference.scrbl]{synchronizable event} with the
@ -74,14 +76,6 @@ Causes the Racket process will wake up and resume polling at the point
when @racket[(current-inexact-milliseconds)] starts returning a value
that is @racket[msecs] or greater.}
Registers a file descriptor (Unix and Mac OS) or socket (all
platforms) to cause the Racket process to wake up if the file
descriptor or socket becomes ready for reading, writing, or error
reporting, as selected by @racket[mode]. The @racket[wakeups] argument
must be a non-@racket[#f] value that is passed by the scheduler to a
@racket[unsafe-poller]-wrapped procedure.}
@defproc[(unsafe-set-sleep-in-thread! [foreground-sleep (-> any/c)]
[fd fixnum?])
void?]{
@ -101,6 +95,6 @@ Racket implementation. It always works for Mac OS.}
@defproc[(unsafe-signal-received) void?]{
For use with @racket[unsafe-set-sleep-in-thread!] by
@racket[foreground-sleep] or something that it triggers, causes the
default sleeping function to request @racket[foreground-sleep] to
@racket[_foreground-sleep] or something that it triggers, causes the
default sleeping function to request @racket[_foreground-sleep] to
return.}

View File

@ -1,7 +1,8 @@
#lang scribble/doc
@(require scribble/struct
"mz.rkt"
(for-label racket/async-channel))
(for-label racket/async-channel
(only-in ffi/unsafe/schedule unsafe-poller)))
@(define evt-eval (make-base-eval))
@ -355,6 +356,11 @@ A @tech{structure type property} that identifies structure types whose
]
@margin-note{For working with foreign libraries, a @racket[prop:evt]
value can also be a result of @racket[unsafe-poller],
although that possibility is omitted from the safe
contract of @racket[prop:evt].}
Instances of a structure type with the @racket[prop:input-port] or
@racket[prop:output-port] property are also @tech{synchronizable events} by virtue
of being a port. If the structure type has more than one of

View File

@ -1,7 +1,8 @@
(load-relative "loadtest.rktl")
(require ffi/unsafe/schedule)
(Section 'synchronization)
(define SYNC-SLEEP-DELAY 0.025)
@ -973,6 +974,37 @@
;; make sure it's ok for rewind to be the first action:
(test (void) thread-wait (thread (lambda () (thread-rewind-receive '(1 2 3)))))
;; ----------------------------------------
;; Unsafe poller
(let ()
(struct p (results)
#:property prop:evt (unsafe-poller
(lambda (self wakeups)
(values (p-results self) #f))))
(test 17 sync (p '(17)))
(test add1 sync (p (list add1)))
(test-values '(16 17) (lambda () (sync (p '(16 17)))))
(test-values '() (lambda () (sync (p '())))))
(let ()
;; Let the scheduler poll up to `counter` times:
(define counter 20)
(struct p ()
#:property prop:evt (unsafe-poller
(lambda (self wakeups)
(cond
[(zero? counter)
(values '(#t) #f)]
[else
(set! counter (sub1 counter))
(when wakeups
;; Cancel any sleep:
(unsafe-poll-ctx-milliseconds-wakeup wakeups (current-inexact-milliseconds)))
(values #f self)]))))
(test #t sync (p)))
;; ----------------------------------------
;; Garbage collection

View File

@ -1646,6 +1646,21 @@ static Scheme_Object *return_wrapped(void *data, int argc, Scheme_Object *argv[]
return (Scheme_Object *)data;
}
static Scheme_Object *return_wrapped_multi(void *data, int argc, Scheme_Object *argv[])
{
Scheme_Object **a, *l = (Scheme_Object *)data;
int i, n;
n = scheme_list_length(l);
a = MALLOC_N(Scheme_Object *, n);
for (i = 0; i < n; i++) {
a[i] = SCHEME_CAR(l);
l = SCHEME_CDR(l);
}
return scheme_values(n, a);
}
static int evt_struct_is_ready(Scheme_Object *o, Scheme_Schedule_Info *sinfo)
{
Scheme_Object *v;
@ -1731,7 +1746,18 @@ static int evt_struct_is_ready(Scheme_Object *o, Scheme_Schedule_Info *sinfo)
scheme_end_in_scheduler();
if (v) {
if (done && SCHEME_PROCP(v)) {
if (done) {
int check_proc = 1;
if (SCHEME_PAIRP(v) && SCHEME_NULLP(SCHEME_CDR(v)) && !SCHEME_PROCP(SCHEME_CAR(v)))
v = SCHEME_CAR(v); /* single result */
else if (!SCHEME_NULLP(v) && !SCHEME_PAIRP(v)) {
/* wrong result, be we allow it for backward compatibility */
} else {
v = scheme_make_closed_prim_w_arity(return_wrapped_multi, (void *)v, "multi-wrapper", 1, 1);
check_proc = 0;
}
if (check_proc && SCHEME_PROCP(v))
v = scheme_make_closed_prim_w_arity(return_wrapped, (void *)v, "wrapper", 1, 1);
}
scheme_set_sync_target(sinfo, v, (done ? v : NULL), NULL, 0, 0, NULL);