doc work, especially threads and continuations reference
svn: r6786
This commit is contained in:
parent
4bcf7111fb
commit
560eb67217
|
@ -274,17 +274,20 @@
|
|||
;; ----------------------------------------
|
||||
|
||||
(define/public (table-of-contents part ht)
|
||||
(make-table #f (render-toc part #t)))
|
||||
(make-table #f (render-toc part
|
||||
(sub1 (length (collected-info-number
|
||||
(part-collected-info part))))
|
||||
#t)))
|
||||
|
||||
(define/public (local-table-of-contents part ht)
|
||||
(table-of-contents part ht))
|
||||
|
||||
(define/private (render-toc part skip?)
|
||||
(define/private (render-toc part base-len skip?)
|
||||
(let ([number (collected-info-number (part-collected-info part))])
|
||||
(let ([subs
|
||||
(apply
|
||||
append
|
||||
(map (lambda (p) (render-toc p #f)) (part-parts part)))])
|
||||
(map (lambda (p) (render-toc p base-len #f)) (part-parts part)))])
|
||||
(if skip?
|
||||
subs
|
||||
(let ([l (cons
|
||||
|
@ -292,7 +295,7 @@
|
|||
(list
|
||||
(make-paragraph
|
||||
(list
|
||||
(make-element 'hspace (list (make-string (* 2 (length number)) #\space)))
|
||||
(make-element 'hspace (list (make-string (* 2 (- (length number) base-len)) #\space)))
|
||||
(make-link-element (if (= 1 (length number))
|
||||
"toptoclink"
|
||||
"toclink")
|
||||
|
|
|
@ -378,6 +378,8 @@
|
|||
(list (make-table style content))))
|
||||
(list (make-table style content))))
|
||||
|
||||
(define max-proto-width 65)
|
||||
|
||||
(define (*defproc stx-ids prototypes arg-contractss result-contracts content-thunk)
|
||||
(let ([spacer (hspace 1)]
|
||||
[has-optional? (lambda (arg)
|
||||
|
@ -437,7 +439,12 @@
|
|||
(let ([req (reverse r-accum)])
|
||||
(let loop ([a a][o-accum null])
|
||||
(if (or (null? a)
|
||||
(not (has-optional? (car a))))
|
||||
(and (not (has-optional? (car a)))
|
||||
;; A repeat after an optional argument is
|
||||
;; effectively optional:
|
||||
(not (memq (car a) '(...)))
|
||||
(or (null? (cdr a))
|
||||
(not (memq (cadr a) '(...))))))
|
||||
(values req (reverse o-accum) a)
|
||||
(loop (cdr a) (cons (car a) o-accum)))))
|
||||
(loop (cdr a) (cons (car a) r-accum))))]
|
||||
|
@ -457,11 +464,12 @@
|
|||
flat-size
|
||||
(prototype-size prototype + max))
|
||||
(flow-element-width res))
|
||||
. >= . 50)]
|
||||
. >= . (- max-proto-width 7))]
|
||||
[(end) (list (to-flow spacer)
|
||||
(to-flow 'rarr)
|
||||
(to-flow spacer)
|
||||
(make-flow (list res)))])
|
||||
(make-flow (list res)))]
|
||||
[(opt-cnt) (length optional)])
|
||||
(append
|
||||
(list
|
||||
(list (make-flow
|
||||
|
@ -512,31 +520,44 @@
|
|||
(arg->elem (car optional))
|
||||
(arg->elem (car required))))
|
||||
not-end)
|
||||
(let loop ([args (cdr (append required optional))]
|
||||
(let loop ([args (cdr (append required optional more-required))]
|
||||
[req (sub1 (length required))])
|
||||
(if (null? args)
|
||||
null
|
||||
(cons (list* (to-flow spacer)
|
||||
(if (zero? req)
|
||||
(to-flow (make-element #f (list spacer "[")))
|
||||
(to-flow spacer))
|
||||
(let ([a (arg->elem (car args))])
|
||||
(to-flow
|
||||
(cond
|
||||
[(null? (cdr args))
|
||||
(if (null? optional)
|
||||
(make-element
|
||||
#f
|
||||
(list a (schemeparenfont ")")))
|
||||
(make-element
|
||||
#f
|
||||
(list a "]" (schemeparenfont ")"))))]
|
||||
[else a])))
|
||||
(if (and (null? (cdr args))
|
||||
(not result-next-line?))
|
||||
end
|
||||
not-end))
|
||||
(loop (cdr args) (sub1 req)))))))))))))
|
||||
(let ([dots-next? (or (and (pair? (cdr args))
|
||||
(or (eq? (cadr args) '...)
|
||||
(eq? (cadr args) '...+))))])
|
||||
(cons (list* (to-flow spacer)
|
||||
(if (zero? req)
|
||||
(to-flow (make-element #f (list spacer "[")))
|
||||
(to-flow spacer))
|
||||
(let ([a (arg->elem (car args))]
|
||||
[next (if dots-next?
|
||||
(make-element #f (list (hspace 1)
|
||||
(arg->elem (cadr args))))
|
||||
"")])
|
||||
(to-flow
|
||||
(cond
|
||||
[(null? ((if dots-next? cddr cdr) args))
|
||||
(if (or (null? optional)
|
||||
(not (null? more-required)))
|
||||
(make-element
|
||||
#f
|
||||
(list a next (schemeparenfont ")")))
|
||||
(make-element
|
||||
#f
|
||||
(list a next "]" (schemeparenfont ")"))))]
|
||||
[(and (pair? more-required)
|
||||
(= (- 1 req) (length optional)))
|
||||
(make-element #f (list a next "]"))]
|
||||
[(equal? next "") a]
|
||||
[else
|
||||
(make-element #f (list a next))])))
|
||||
(if (and (null? ((if dots-next? cddr cdr) args))
|
||||
(not result-next-line?))
|
||||
end
|
||||
not-end))
|
||||
(loop ((if dots-next? cddr cdr) args) (sub1 req))))))))))))))
|
||||
(if result-next-line?
|
||||
(list (list (make-flow (make-table-if-necessary
|
||||
"prototype"
|
||||
|
@ -546,29 +567,52 @@
|
|||
(map (lambda (v arg-contract)
|
||||
(cond
|
||||
[(pair? v)
|
||||
(list
|
||||
(list
|
||||
(make-flow
|
||||
(make-table-if-necessary
|
||||
"argcontract"
|
||||
(list
|
||||
(let ([v (if (keyword? (car v))
|
||||
(cdr v)
|
||||
v)])
|
||||
(append
|
||||
(let* ([v (if (keyword? (car v))
|
||||
(cdr v)
|
||||
v)]
|
||||
[arg-cont (arg-contract)]
|
||||
[base-len (+ 5 (string-length (symbol->string (car v)))
|
||||
(flow-element-width arg-cont))]
|
||||
[def-len (if (has-optional? v)
|
||||
(string-length (format "~a" (caddr v)))
|
||||
0)]
|
||||
[base-list
|
||||
(list
|
||||
(to-flow (hspace 2))
|
||||
(to-flow (arg->elem v))
|
||||
(to-flow spacer)
|
||||
(to-flow ":")
|
||||
(to-flow spacer)
|
||||
(make-flow (list (arg-contract))))
|
||||
(if (has-optional? v)
|
||||
(list (to-flow spacer)
|
||||
(to-flow "=")
|
||||
(to-flow spacer)
|
||||
(to-flow (to-element (caddr v))))
|
||||
null))))))))]
|
||||
(make-flow (list arg-cont)))])
|
||||
(list
|
||||
(list
|
||||
(make-flow
|
||||
(if (and (has-optional? v)
|
||||
((+ base-len 3 def-len) . >= . max-proto-width))
|
||||
(list
|
||||
(make-table
|
||||
"argcontract"
|
||||
(list
|
||||
base-list
|
||||
(list
|
||||
(to-flow spacer)
|
||||
(to-flow spacer)
|
||||
(to-flow spacer)
|
||||
(to-flow "=")
|
||||
(to-flow spacer)
|
||||
(to-flow (to-element (caddr v)))))))
|
||||
(make-table-if-necessary
|
||||
"argcontract"
|
||||
(list
|
||||
(append
|
||||
base-list
|
||||
(if (and (has-optional? v)
|
||||
((+ base-len 3 def-len) . < . max-proto-width))
|
||||
(list (to-flow spacer)
|
||||
(to-flow "=")
|
||||
(to-flow spacer)
|
||||
(to-flow (to-element (caddr v))))
|
||||
null)))))))))]
|
||||
[else null]))
|
||||
(cdr prototype)
|
||||
arg-contracts)))))
|
||||
|
@ -815,6 +859,11 @@
|
|||
(define (commandline . s)
|
||||
(make-paragraph (list (hspace 2) (apply tt s))))
|
||||
|
||||
(define (elemtag t . body)
|
||||
(make-target-element #f (decode-content body) t))
|
||||
(define (elemref t . body)
|
||||
(make-link-element #f (decode-content body) t))
|
||||
(provide elemtag elemref)
|
||||
|
||||
(define (secref s)
|
||||
(make-link-element #f null `(part ,s)))
|
||||
|
|
134
collects/scribblings/reference/breaks.scrbl
Normal file
134
collects/scribblings/reference/breaks.scrbl
Normal file
|
@ -0,0 +1,134 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:breakhandler"]{Breaks}
|
||||
|
||||
@index['("threads" "breaking")]{A} @deftech{break} is an asynchronous
|
||||
exception, usually triggered through an external source controlled by
|
||||
the user, or through the @scheme[break-thread] procedure. A break
|
||||
exception can only occur in a thread while breaks are enabled. When a
|
||||
break is detected and enabled, the @exnraise[exn:break] in the thread
|
||||
sometime afterward; if breaking is disabled when @scheme[break-thread]
|
||||
is called, the break is suspended until breaking is again enabled for
|
||||
the thread. While a thread has a suspended break, additional breaks
|
||||
are ignored.
|
||||
|
||||
Breaks are enabled through the @scheme[break-enabled] parameter-like
|
||||
procedure, and through the @scheme[parameterize-break] form, which is
|
||||
analogous to @scheme[parameterize]. The @scheme[break-enabled]
|
||||
procedure does not represent a parameter to be used with
|
||||
@scheme[parameterize], because changing the break-enabled state of a
|
||||
thread requires an explicit check for breaks, and this check is
|
||||
incompatible with the tail evaluation of a @scheme[parameterize]
|
||||
expression's body.
|
||||
|
||||
Certain procedures, such as @scheme[semaphore-wait/enable-break],
|
||||
enable breaks temporarily while performing a blocking action. If
|
||||
breaks are enabled for a thread, and if a break is triggered for the
|
||||
thread but not yet delivered as an @scheme[exn:break] exception, then
|
||||
the break is guaranteed to be delivered before breaks can be disabled
|
||||
in the thread. The timing of @scheme[exn:break] exceptions is not
|
||||
guaranteed in any other way.
|
||||
|
||||
Before calling a @scheme[with-handlers] predicate or handler, an
|
||||
exception handler, an error display handler, an error escape handler,
|
||||
an error value conversion handler, or a @scheme[pre-thunk] or
|
||||
@scheme[post-thunk] for a @scheme[dynamic-wind], the call is
|
||||
@scheme[parameterize-break]ed to disable breaks. Furthermore, breaks
|
||||
are disabled during the transitions among handlers related to
|
||||
exceptions, during the transitions between @scheme[pre-thunk]s and
|
||||
@scheme[post-thunk]s for @scheme[dynamic-wind], and during other
|
||||
transitions for a continuation jump. For example, if breaks are
|
||||
disabled when a continuation is invoked, and if breaks are also
|
||||
disabled in the target continuation, then breaks will remain disabled
|
||||
until from the time of the invocation until the target continuation
|
||||
executes unless a relevant @scheme[dynamic-wind] @scheme[pre-thunk] or
|
||||
@scheme[post-thunk] explicitly enables breaks.
|
||||
|
||||
If a break is triggered for a thread that is blocked on a nested
|
||||
thread (see @scheme[call-in-nested-thread]), and if breaks are enabled
|
||||
in the blocked thread, the break is implicitly handled by transferring
|
||||
it to the nested thread.
|
||||
|
||||
When breaks are enabled, they can occur at any point within execution,
|
||||
which makes certain implementation tasks subtle. For example, assuming
|
||||
breaks are enabled when the following code is executed,
|
||||
|
||||
@schemeblock[
|
||||
(with-handlers ([exn:break? (lambda (x) (void))])
|
||||
(semaphore-wait s))
|
||||
]
|
||||
|
||||
then it is @italic{not} the case that a @|void-const| result means the
|
||||
semaphore was decremented or a break was received, exclusively. It is
|
||||
possible that @italic{both} occur: the break may occur after the
|
||||
semaphore is successfully decremented but before a @|void-const|
|
||||
result is returned by @scheme[semaphore-wait]. A break exception will
|
||||
never damage a semaphore, or any other built-in construct, but many
|
||||
built-in procedures (including @scheme[semaphore-wait]) contain
|
||||
internal sub-expressions that can be interrupted by a break.
|
||||
|
||||
In general, it is impossible using only @scheme[semaphore-wait] to
|
||||
implement the guarantee that either the semaphore is decremented or an
|
||||
exception is raised, but not both. Scheme therefore supplies
|
||||
@scheme[semaphore-wait/enable-break] (see @secref["mz:semaphore"]),
|
||||
which does permit the implementation of such an exclusive guarantee:
|
||||
|
||||
@schemeblock[
|
||||
(parameterize ([break-enabled #f])
|
||||
(with-handlers ([exn:break? (lambda (x) (void))])
|
||||
(semaphore-wait/enable-break s)))
|
||||
]
|
||||
|
||||
In the above expression, a break can occur at any point until breaks
|
||||
are disabled, in which case a break exception is propagated to the
|
||||
enclosing exception handler. Otherwise, the break can only occur
|
||||
within @scheme[semaphore-wait/enable-break], which guarantees that if
|
||||
a break exception is raised, the semaphore will not have been
|
||||
decremented.
|
||||
|
||||
To allow similar implementation patterns over blocking port
|
||||
operations, MzScheme provides @scheme[read-bytes-avail!/enable-break]
|
||||
(see @secref["mz:read"]), @scheme[write-bytes-avail/enable-break] (see
|
||||
@secref["mz:write"]), and other procedures.
|
||||
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
@defproc*[([(break-enabled) boolean?]
|
||||
[(break-enabled [on? any/c]) void?])]{
|
||||
|
||||
Gets or sets the break enabled state of the current thread. If
|
||||
@scheme[on?] is not supplied, the result is @scheme[#t] if breaks are
|
||||
currently enabled, @scheme[#f] otherwise. If @scheme[on?] is supplied
|
||||
as @scheme[#f], breaks are disabled, and if @scheme[on?] is a true
|
||||
value, breaks are enabled.}
|
||||
|
||||
@defform[(parameterize-break boolean-expr body ...+)]{Evaluates
|
||||
@scheme[boolean-expr] to determine whether breaks are initially
|
||||
enabled in while evaluating the @scheme[body]s in sequence. The result
|
||||
of the @scheme[parameter-break] expression is the result of the last
|
||||
@scheme[expr].
|
||||
|
||||
Like @scheme[parameterize] (see @secref["mz:parameters"]), a fresh
|
||||
@tech{thread cell} (see @secref["mz:threadcells"]) is allocated to
|
||||
hold the break-enabled state of the continuation, and calls to
|
||||
@scheme[break-enabled] within the continuation access or modify the
|
||||
new cell. Unlike parameters, the break setting is not inherited by new
|
||||
threads.}
|
||||
|
||||
@defproc[(current-break-parameterization) break-parameterization?]{
|
||||
Analogous to @scheme[(current-parameterization)] (see
|
||||
@secref["mz:parameters"]); it returns a break-parameterization
|
||||
(effectively a thread cell) that holds the current continuation's
|
||||
break-enable state.}
|
||||
|
||||
@defproc[(call-with-break-parameterization
|
||||
[break-param break-parameterization?]
|
||||
[thunk (-> any)])
|
||||
any]{
|
||||
Analogous to @scheme[(call-with-parameterization parameterization
|
||||
thunk)] (see @secref["mz:parameters"]), calls @scheme[thunk] in a
|
||||
continuation whose break-enabled state is in @scheme[break-param]. The
|
||||
@scheme[thunk] is @italic{not} called in tail position with respect to
|
||||
the @scheme[call-with-break-parameterization] call.}
|
56
collects/scribblings/reference/channels.scrbl
Normal file
56
collects/scribblings/reference/channels.scrbl
Normal file
|
@ -0,0 +1,56 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "bnf.ss" "scribble")]
|
||||
@require["mz.ss"]
|
||||
|
||||
|
||||
@title[#:tag "mz:channel"]{Channels}
|
||||
|
||||
A @deftech{channel} both synchronizes a pair of threads and passes a
|
||||
value from one to the other. Channels are synchronous; both the sender
|
||||
and the receiver must block until the (atomic) transaction is
|
||||
complete. Multiple senders and receivers can access a channel at once,
|
||||
but a single sender and receiver is selected for each transaction.
|
||||
|
||||
Channel synchronization is @defterm{fair}: if a thread is blocked on a
|
||||
channel and transaction opportunities for the channel occur infinitely
|
||||
often, then the thread eventually participates in a transaction.
|
||||
|
||||
For buffered asynchronous channels, see @secref["mz:async-channel"].
|
||||
|
||||
@defproc[(make-channel) channel?]{
|
||||
|
||||
Creates and returns a new channel. The channel can be used with
|
||||
@scheme[channel-get], with @scheme[channel-try-get], or as a
|
||||
@tech{synchronizable event} (see @secref["mz:sync"]) to receive a value
|
||||
through the channel. The channel can be used with @scheme[channel-put]
|
||||
or through the result of @scheme[channel-put-evt] to send a value
|
||||
through the channel.}
|
||||
|
||||
@defproc[(channel? [v any/c]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[v] is a channel created by
|
||||
@scheme[make-channel], @scheme[#f] otherwise.}
|
||||
|
||||
|
||||
@defproc[(channel-get [ch channel?]) any]{
|
||||
|
||||
Blocks until a sender is ready to provide a value through
|
||||
@scheme[ch]. The result is the sent value.}
|
||||
|
||||
@defproc[(channel-try-get [ch channel?]) any]{
|
||||
|
||||
Receives and returns a value from @scheme[ch] if a sender is
|
||||
immediately ready, otherwise returns @scheme[#f].}
|
||||
|
||||
@defproc[(channel-put [ch channel?][v any/c]) void?]{
|
||||
|
||||
Blocks until a receiver is ready to accept the value @scheme[v]
|
||||
through @scheme[ch].}
|
||||
|
||||
|
||||
@defproc[(channel-put-evt [ch channel?][v any/c]) evt?]{
|
||||
|
||||
Returns a fresh @tech{synchronizable event} for use with
|
||||
@scheme[sync]. The event is ready when @scheme[(channel-put ch v)]
|
||||
would not block, and the event's synchronization result is the event
|
||||
itself.}
|
21
collects/scribblings/reference/concurrency.scrbl
Normal file
21
collects/scribblings/reference/concurrency.scrbl
Normal file
|
@ -0,0 +1,21 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "bnf.ss" "scribble")]
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:concurrency" #:style 'toc]{Concurrency}
|
||||
|
||||
PLT Scheme supports multiple threads of control within a
|
||||
program. Threads run concurrently, in the sense that one thread can
|
||||
preempt another without its cooperation, but threads currently all run
|
||||
on the same processor (i.e., the same underlying OS process and
|
||||
thread).
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
@include-section["threads.scrbl"]
|
||||
@include-section["sync.scrbl"]
|
||||
@include-section["thread-local.scrbl"]
|
||||
|
||||
|
168
collects/scribblings/reference/cont-marks.scrbl
Normal file
168
collects/scribblings/reference/cont-marks.scrbl
Normal file
|
@ -0,0 +1,168 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "struct.ss" "scribble")]
|
||||
@require["mz.ss"]
|
||||
|
||||
@define[(cont n) (make-element "schemevariable"
|
||||
(list "C" (make-element 'subscript (list (format "~a" n)))))]
|
||||
|
||||
@title[#:tag "mz:contmarks"]{Continuation Marks}
|
||||
|
||||
See @secref["mz:mark-model"] and @secref["mz:prompt-model"] for
|
||||
general information about continuation marks.
|
||||
|
||||
The list of continuation marks for a key @scheme[_k] and a continuation
|
||||
@scheme[_C] that extends @cont[0] is defined as follows:
|
||||
%
|
||||
@itemize{
|
||||
|
||||
@item{If @scheme[_C] is an empty continuation, then the mark list is
|
||||
@scheme[null].}
|
||||
|
||||
@item{If @scheme[_C]'s first frame contains a mark @scheme[_m] for @scheme[_k],
|
||||
then the mark list for @scheme[_C] is @scheme[(cons @scheme[_m] _lst)],
|
||||
where @scheme[_lst] is the mark list for @scheme[_k] in @cont[0].}
|
||||
|
||||
@item{If @scheme[_C]'s first frame does not contain a mark keyed by
|
||||
@scheme[_k], then the mark list for @scheme[_C] is the mark list for
|
||||
@cont[0].}
|
||||
|
||||
}
|
||||
|
||||
The @scheme[with-continuation-mark] form installs a mark on the first
|
||||
frame of the current continuation (see @secref["mz:wcm"]). Procedures
|
||||
such as @scheme[current-continuation-marks] allow inspection of marks.
|
||||
|
||||
Whenever Scheme creates an exception record for a primitive exception,
|
||||
it fills the @scheme[continuation-marks] field with the value of
|
||||
@scheme[(current-continuation-marks)], thus providing a snapshot of
|
||||
the continuation marks at the time of the exception.
|
||||
|
||||
When a continuation procedure returned by
|
||||
@scheme[call-with-current-continuation] or
|
||||
@scheme[call-with-composable-continuation] is invoked, it restores the
|
||||
captured continuation, and also restores the marks in the
|
||||
continuation's frames to the marks that were present when
|
||||
@scheme[call-with-current-continuation] or
|
||||
@scheme[call-with-composable-continuation] was invoked.
|
||||
|
||||
@defproc[(continuation-marks [cont continuation?]
|
||||
[prompt-tag prompt-tag? (default-continuation-prompt-tag)])
|
||||
continuation-mark-set?]{
|
||||
|
||||
Returns an opaque value containing the set of continuation marks for
|
||||
all keys in the continuation @scheme[cont] up to the prompt tagged by
|
||||
@scheme[prompt-tag]. If @scheme[cont] is an escape continuation (see
|
||||
@secref["mz:prompt-model"]), then the current continuation must extend
|
||||
@scheme[cont], or the @exnraise[exn:fail:contract]. If @scheme[cont]
|
||||
was not captured with respect to @scheme[prompt-tag] and does not
|
||||
include a prompt for @scheme[prompt-tag], the
|
||||
@exnraise[exn:fail:contract].}
|
||||
|
||||
@defproc[(current-continuation-marks [prompt-tag prompt-tag? (default-continuation-prompt-tag)])
|
||||
continuation-mark-set?]{
|
||||
|
||||
Returns an opaque value containing the set of continuation marks for
|
||||
all keys in the current continuation up to @scheme[prompt-tag]. In
|
||||
other words, it produces the same value as
|
||||
|
||||
@schemeblock[
|
||||
(call-with-current-continuation
|
||||
(lambda (k)
|
||||
(continuation-marks k prompt-tag))
|
||||
prompt-tag)
|
||||
]}
|
||||
|
||||
@defproc[(continuation-mark-set->list
|
||||
[mark-set continuation-mark-set?]
|
||||
[key-v any/c]
|
||||
[prompt-tag prompt-tag? (default-continuation-prompt-tag)])
|
||||
list?]{
|
||||
Returns a newly-created list containing the marks for @scheme[key-v]
|
||||
in @scheme[mark-set], which is a set of marks returned by
|
||||
@scheme[current-continuation-marks]. The result list is truncated at
|
||||
the first point, if any, where continuation frames were originally
|
||||
separated by a prompt tagged with @scheme[prompt-tag]..}
|
||||
|
||||
@defproc[(continuation-mark-set->list*
|
||||
[mark-set continuation-mark-set?]
|
||||
[key-v any/c]
|
||||
[none-v any/c #f]
|
||||
[prompt-tag prompt-tag? (default-continuation-prompt-tag)])
|
||||
(listof vector?)]{
|
||||
Returns a newly-created list containing vectors of marks in
|
||||
@scheme[mark-set] for the keys in @scheme[key-list], up to
|
||||
@scheme[prompt-tag]. The length of each vector in the result list is
|
||||
the same as the length of @scheme[key-list], and a value in a
|
||||
particular vector position is the value for the corresponding key in
|
||||
@scheme[key-list]. Values for multiple keys appear in a single vector
|
||||
only when the marks are for the same continuation frame in
|
||||
@scheme[mark-set]. The @scheme[none-v] argument is used for vector
|
||||
elements to indicate the lack of a value.}
|
||||
|
||||
@defproc[(continuation-mark-set-first
|
||||
[mark-set (or/c continuation-mark-set? false/c)]
|
||||
[key-v any/c]
|
||||
[prompt-tag prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
Returns the first element of the list that would be returned by
|
||||
@scheme[(continuation-mark-set->list (or mark-set
|
||||
(current-continuation-marks prompt-tag)) key-v prompt-tag)], or
|
||||
@scheme[#f] if the result would be the empty list. Typically, this
|
||||
result can be computed more quickly using
|
||||
@scheme[continuation-mark-set-first].}
|
||||
|
||||
@defproc[(continuation-mark-set? [v any/c]) boolean?]{
|
||||
Returns @scheme[#t] if @scheme[v] is a mark set created by
|
||||
@scheme[continuation-marks] or @scheme[current-continuation-marks],
|
||||
@scheme[#f] otherwise.}
|
||||
|
||||
@defproc[(continuation-mark-set->context
|
||||
[mark-set continuation-mark-set?])
|
||||
list?]{
|
||||
|
||||
Returns a list representing a ``stack trace'' for @scheme[mark-set]'s
|
||||
continuation. The list contains pairs, where the @scheme[car] of each
|
||||
pair contains either @scheme[#f] or a symbol for a procedure name, and
|
||||
the @scheme[cdr] of each pair contains either @scheme[#f] or a
|
||||
@scheme[srcloc] value for the procedure's source location (see
|
||||
@secref["mz:linecol"]); the @scheme[car] and @scheme[cdr] are never
|
||||
both @scheme[#f].
|
||||
|
||||
The stack-trace list is the result of
|
||||
@scheme[continuation-mark-set->list] with @scheme[mark-set] and
|
||||
Scheme's private key for procedure-call marks. A stack trace is
|
||||
extracted from an exception and displayed by the default error display
|
||||
handler (see @secref["mz:exnsandflow"]) for exceptions other than
|
||||
@scheme[exn:fail:user] (see @scheme[raise-user-error] in
|
||||
@secref["mz:errorproc"]).}
|
||||
|
||||
@examples[
|
||||
(define (extract-current-continuation-marks key)
|
||||
(continuation-mark-set->list
|
||||
(current-continuation-marks)
|
||||
key))
|
||||
|
||||
(with-continuation-mark 'key 'mark
|
||||
(extract-current-continuation-marks 'key))
|
||||
|
||||
(with-continuation-mark 'key1 'mark1
|
||||
(with-continuation-mark 'key2 'mark2
|
||||
(list
|
||||
(extract-current-continuation-marks 'key1)
|
||||
(extract-current-continuation-marks 'key2))))
|
||||
|
||||
(with-continuation-mark 'key 'mark1
|
||||
(with-continuation-mark 'key 'mark2 (code:comment @t{replaces the previous mark})
|
||||
(extract-current-continuation-marks 'key)))
|
||||
|
||||
(with-continuation-mark 'key 'mark1
|
||||
(list (code:comment @t{continuation extended to evaluate the argument})
|
||||
(with-continuation-mark 'key 'mark2
|
||||
(extract-current-continuation-marks 'key))))
|
||||
|
||||
(let loop ([n 1000])
|
||||
(if (zero? n)
|
||||
(extract-current-continuation-marks 'key)
|
||||
(with-continuation-mark 'key n
|
||||
(loop (sub1 n)))))
|
||||
]
|
341
collects/scribblings/reference/cont.scrbl
Normal file
341
collects/scribblings/reference/cont.scrbl
Normal file
|
@ -0,0 +1,341 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:cont"]{Continuations}
|
||||
|
||||
See @secref["mz:cont-model"] and @secref["mz:prompt-model"] for
|
||||
general information about continuations. PLT Scheme's support for
|
||||
prompts and composable continuations most closely resembles Dorai
|
||||
Sitaram's @scheme[\%] and @scheme[fcontrol] operator @cite[#:key
|
||||
"cite:fcontrol" #:title "Handling Control" #:author "Dorai Sitaram"
|
||||
#:location "Programming Language Design and Implementation" #:date
|
||||
1993].
|
||||
|
||||
Scheme installs a @defterm{continuation barrier} around evaluation in
|
||||
the following contexts, preventing full-continuation jumps across the
|
||||
barrier:
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{applying an exception handler, an error escape handler, or an
|
||||
error display handler (see @secref["mz:exns"]);}
|
||||
|
||||
@item{applying a macro transformer (see @secref["mz:stxtrans"]),
|
||||
evaluating a compile-time expression, or applying a module name
|
||||
resolver (see @secref["mz:modnameresolver"]);}
|
||||
|
||||
@item{applying a custom-port procedure (see @secref["mz:customport"]), an
|
||||
event guard procedure (see @secref["mz:sync"]), or a parameter guard
|
||||
procedure (see @secref["mz:parameters"]);}
|
||||
|
||||
@item{applying a security-guard procedure (see
|
||||
@secref["mz:securityguards"]);}
|
||||
|
||||
@item{applying a will procedure (see @secref["mz:willexecutor"]); or}
|
||||
|
||||
@item{evaluating or loading code from the stand-alone MzScheme
|
||||
command line (see @secref["mz:running-sa"]).}
|
||||
|
||||
}
|
||||
|
||||
In addition, extensions of PLT Scheme may install barriers in
|
||||
additional contexts. In particular, MrEd installs a continuation
|
||||
barrier around most every callback. Finally,
|
||||
@scheme[call-with-continuation-barrier] applies a thunk barrier
|
||||
between the application and the current continuation.
|
||||
|
||||
|
||||
@defproc[(call-with-continuation-prompt
|
||||
[thunk (-> any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]
|
||||
[handler (or/c procedure? false/c) #f])
|
||||
any]{
|
||||
|
||||
Calls @scheme[thunk] with the current continuation extended by a
|
||||
prompt. The prompt is tagged by @scheme[prompt-tag], which must be a
|
||||
result from either @scheme[default-continuation-prompt-tag] (the
|
||||
default) or @scheme[make-continuation-prompt-tag]. The result of
|
||||
@scheme[thunk] is the result of the
|
||||
@scheme[call-with-continuation-prompt] call.
|
||||
|
||||
The @scheme[handler] argument specifies a handler procedure to be
|
||||
called in tail position with repsect to the
|
||||
@scheme[call-with-continuation-prompt] call when the installed prompt
|
||||
is the target of a @scheme[abort-current-continuation] call with
|
||||
@scheme[prompt-tag]; the remaining arguments of
|
||||
@scheme[abort-current-continuation] are supplied to the handler
|
||||
procedure. If @scheme[handler] is @scheme[#f], the default handler
|
||||
accepts a single @scheme[abort-thunk] argument and calls
|
||||
@scheme[(call-with-continuation-prompt abort-thunk prompt-tag #f)];
|
||||
that is, the default handler re-installs the prompt and continues with
|
||||
a given thunk.}
|
||||
|
||||
@defproc[(abort-current-continuation
|
||||
[prompt-tag any/c]
|
||||
[v any/c] ...+)
|
||||
any]{
|
||||
|
||||
Resets the current continuation to that of the nearest prompt tagged
|
||||
by @scheme[prompt-tag] in the current continuation; if no such prompt exists,
|
||||
the @exnraise[exn:fail:contract:continuation]. The @scheme[v]s are delivered
|
||||
as arguments to the target prompt's handler procedure.
|
||||
|
||||
The protocol for @scheme[v]s supplied to an abort is specific to the
|
||||
@scheme[prompt-tag]. When @scheme[abort-current-continuation] is used with
|
||||
@scheme[(default-continuation-prompt-tag)], generally a single thunk
|
||||
should be supplied that is suitable for use with the default prompt
|
||||
handler. Similarly, when @scheme[call-with-continuation-prompt] is
|
||||
used with @scheme[(default-continuation-prompt-tag)], the associated
|
||||
handler should generally accept a single thunk argument.}
|
||||
|
||||
@defproc*[([(make-continuation-prompt-tag) continuation-prompt-tag?]
|
||||
[(make-continuation-prompt-tag [sym symbol?]) continuation-prompt-tag?])]{
|
||||
|
||||
Creates a prompt tag that is not @scheme[equal?] to the result of any
|
||||
other value (including prior or future results from
|
||||
@scheme[make-continuation-prompt-tag]). The optional @scheme[sym]
|
||||
argument, if supplied, is used when printing the prompt tag.}
|
||||
|
||||
@defproc[(default-continuation-prompt-tag) continuation-prompt-tag?]{
|
||||
|
||||
Returns a constant prompt tag for a which a prompt is installed at the
|
||||
start of every thread's continuation; the handler for each thread's
|
||||
initial prompt accepts any number of values and returns. The result of
|
||||
@scheme[default-continuation-prompt-tag] is the default tag for more
|
||||
any procedure that accepts a prompt tag.}
|
||||
|
||||
@defproc[(call-with-current-continuation
|
||||
[proc (continuation? . -> . any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
|
||||
Captures the current continuation up to the nearest prompt tagged by
|
||||
@scheme[prompt-tag]; if no such prompt exists, the
|
||||
@exnraise[exn:fail:contract:continuation]. The truncated continuation
|
||||
includes only continuation marks and @scheme[dynamic-wind] frames
|
||||
installed since the prompt.
|
||||
|
||||
The capture continuation is delivered to @scheme[proc], which is
|
||||
called in tail position with respect to the
|
||||
@scheme[call-with-current-continuation] call.
|
||||
|
||||
If the continuation argument to @scheme[proc] is ever applied, then it
|
||||
removes the portion of the current continuation up to the nearest
|
||||
prompt tagged by @scheme[prompt-tag] (not including the prompt; if no
|
||||
such prompt exists, the @exnraise[exn:fail:contract:continuation]), or
|
||||
up to the nearest continuation frame (if any) shared by the current
|
||||
and captured continuations---whichever is first. While removing
|
||||
continuation frames, @scheme[dynamic-wind] @scheme[post-thunk]s are
|
||||
executed. Finally, the (unshared portion of the) captured continuation
|
||||
is appended to the remaining continuation, applying
|
||||
@scheme[dynamic-wind] @scheme[pre-thunk]s.
|
||||
|
||||
The arguments supplied to an applied procedure become the result
|
||||
values for the restored continuation. In particular, if multiple
|
||||
arguments are supplied, then the continuation receives multiple
|
||||
results.
|
||||
|
||||
If, at application time, a continuation barrier appears between the
|
||||
current continuation and the prompt tagged with @scheme[prompt-tag],
|
||||
and if the same barrier is not part of the captured continuation, then
|
||||
the @exnraise[exn:fail:contract:continuation].
|
||||
|
||||
A continuation can be invoked from the thread (see
|
||||
@secref["mz:threads"]) other than the one where it was captured.}
|
||||
|
||||
@defproc[(call/cc
|
||||
[proc (continuation? . -> . any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
|
||||
The @scheme[call/cc] binding is an alias for @scheme[call-with-current-continuation].
|
||||
}
|
||||
|
||||
@defproc[(call-with-composable-continuation
|
||||
[proc (continuation? . -> . any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
|
||||
Similar to @scheme[call-with-current-continuation], but applying
|
||||
the resulting continuation procedure does not remove any portion of
|
||||
the current continuation. Instead, application always extends the
|
||||
current continuation with the captured continuation (without
|
||||
installing any prompts other than those be captured in the
|
||||
continuation). When @scheme[call-with-composable-continuation] is
|
||||
called, if a continuation barrier appears in the continuation before
|
||||
the closest prompt tagged by @scheme[prompt-tag], the
|
||||
@exnraise[exn:fail:contract:continuation].}
|
||||
|
||||
@defproc[(call-with-escape-continuation
|
||||
[proc (continuation? . -> . any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
|
||||
Like @scheme[call-with-current-continuation], but @scheme[proc] is not
|
||||
called in tail position, and the continuation procedure supplied to
|
||||
@scheme[proc] can only be called during the dynamic extent of the
|
||||
@scheme[call-with-escape-continuation] call. A continuation barrier,
|
||||
however, never prevents the application of the continuation.
|
||||
|
||||
Due to the limited applicability of its continuation,
|
||||
@scheme[call-with-escape-continuation] can be implemented more efficiently
|
||||
than @scheme[call-with-current-continuation].
|
||||
|
||||
A continuation obtained from @scheme[call-with-escape-continuation] is
|
||||
actually a kind of prompt. Escape continuations are provided mainly
|
||||
for backward compatibility, since they pre-date general prompts in
|
||||
MzScheme, and because @scheme[call/ec] is often an easy replacement
|
||||
for @scheme[call/cc] to improve performance.}
|
||||
|
||||
@defproc[(call/ec
|
||||
[proc (continuation? . -> . any)]
|
||||
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
||||
any]{
|
||||
|
||||
The @scheme[call/ec] binding is an alias for @scheme[call-with-escape-continuation].
|
||||
}
|
||||
|
||||
@defform[(let/cc k body ...+)]{
|
||||
Equivalent to @scheme[(call/cc (lambda (k) body ...))].
|
||||
}
|
||||
|
||||
@defform[(let/ec k body ...+)]{
|
||||
Equivalent to @scheme[(call/ec (lambda (k) body ...))].
|
||||
}
|
||||
|
||||
@defproc[(call-with-continuation-barrier [thunk (-> any)]) any]{
|
||||
|
||||
Applies @scheme[thunk] with a barrier between the application and the
|
||||
current continuation. The results of @scheme[thunk] are the results of
|
||||
the @scheme[call-with-continuation-barrier] call.}
|
||||
|
||||
|
||||
@defproc[(continuation-prompt-available?
|
||||
[prompt-tag continuation-prompt-tag?]
|
||||
[cont continuation? (call/cc values)])
|
||||
any]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[cont], which must be a continuation,
|
||||
includes a prompt tagged by @scheme[prompt-tag], @scheme[#f]
|
||||
otherwise.
|
||||
}
|
||||
|
||||
@defproc[(continuation? [v any/c]) boolean?]{ Return @scheme[#t] if
|
||||
@scheme[v] is a continuation as produced by
|
||||
@scheme[call-with-current-continuation],
|
||||
@scheme[call-with-composable-continuation], or
|
||||
@scheme[call-with-escape-continuation], @scheme[#f] otherwise.}
|
||||
|
||||
@defproc[(continuation-prompt-tag? [v any/c]) boolean?]{
|
||||
Returns @scheme[#t] if @scheme[v] is a continuation prompt tag as produced by
|
||||
@scheme[default-continuation-prompt-tag] or @scheme[make-continuation-prompt-tag].}
|
||||
|
||||
@defproc[(dynamic-wind [pre-thunk (-> any)]
|
||||
[value-thunk (-> any)]
|
||||
[post-thunk (-> any)])
|
||||
any]{
|
||||
|
||||
Applies its three thunk arguments in order. The value of a
|
||||
@scheme[dynamic-wind] expression is the value returned by
|
||||
@scheme[value-thunk]. The @scheme[pre-thunk] procedure is invoked
|
||||
before calling @scheme[value-thunk] and @scheme[post-thunk] is invoked
|
||||
after @scheme[value-thunk] returns. The special properties of
|
||||
@scheme[dynamic-wind] are manifest when control jumps into or out of
|
||||
the @scheme[value-thunk] application (either due to a prompt abort or
|
||||
a continuation invocation): every time control jumps into the
|
||||
@scheme[value-thunk] application, @scheme[pre-thunk] is invoked, and
|
||||
every time control jumps out of @scheme[value-thunk],
|
||||
@scheme[post-thunk] is invoked. (No special handling is performed for
|
||||
jumps into or out of the @scheme[pre-thunk] and @scheme[post-thunk]
|
||||
applications.)
|
||||
|
||||
When @scheme[dynamic-wind] calls @scheme[pre-thunk] for normal
|
||||
evaluation of @scheme[value-thunk], the continuation of the
|
||||
@scheme[pre-thunk] application calls @scheme[value-thunk] (with
|
||||
@scheme[dynamic-wind]'s special jump handling) and then
|
||||
@scheme[post-thunk]. Similarly, the continuation of the
|
||||
@scheme[post-thunk] application returns the value of the preceding
|
||||
@scheme[value-thunk] application to the continuation of the entire
|
||||
@scheme[dynamic-wind] application.
|
||||
|
||||
When @scheme[pre-thunk] is called due to a continuation jump, the
|
||||
continuation of @scheme[pre-thunk]
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{jumps to a more deeply nested @scheme[pre-thunk], if any, or jumps
|
||||
to the destination continuation; then}
|
||||
|
||||
@item{continues with the context of the @scheme[pre-thunk]'s
|
||||
@scheme[dynamic-wind] call.}
|
||||
|
||||
}
|
||||
|
||||
Normally, the second part of this continuation is never reached, due
|
||||
to a jump in the first part. However, the second part is relevant
|
||||
because it enables jumps to escape continuations that are contained in
|
||||
the context of the @scheme[dynamic-wind] call. Furthermore, it means
|
||||
that the continuation marks (see @secref["mz:contmarks"]) and
|
||||
parameterization (see @secref["mz:parameters"]) for @scheme[pre-thunk]
|
||||
correspond to those of the @scheme[dynamic-wind] call that installed
|
||||
@scheme[pre-thunk]. The @scheme[pre-thunk] call, however, is
|
||||
@scheme[parameterize-break]ed to disable breaks (see also
|
||||
@secref["mz:breakhandler"]).
|
||||
|
||||
Similarly, when @scheme[post-thunk] is called due to a continuation
|
||||
jump, the continuation of @scheme[post-thunk] jumps to a less deeply
|
||||
nested @scheme[post-thunk], if any, or jumps to a @scheme[pre-thunk]
|
||||
protecting the destination, if any, or jumps to the destination
|
||||
continuation, then continues from the @scheme[post-thunk]'s
|
||||
@scheme[dynamic-wind] application. As for @scheme[pre-thunk], the
|
||||
parameterization of the original @scheme[dynamic-wind] call is
|
||||
restored for the call, and the call is @scheme[parameterize-break]ed
|
||||
to disable breaks.
|
||||
|
||||
In both cases, the target for a jump is recomputed after each
|
||||
@scheme[pre-thunk] or @scheme[post-thunk] completes. When a
|
||||
prompt-delimited continuation (see @secref["mz:prompts"]) is captured
|
||||
in a @scheme[post-thunk], it might be delimited and instantiated in
|
||||
such a way that the target of a jump turns out to be different when
|
||||
the continuation is applied than when the continuation was
|
||||
captured. There may even be no appropriate target, if a relevant
|
||||
prompt or escape continuation is not in the continuation after the
|
||||
restore; in that case, the first step in a @scheme[pre-thunk] or
|
||||
@scheme[post-thunk]'s continuation can raise an exception.
|
||||
|
||||
@examples[
|
||||
(let ([v (let/ec out
|
||||
(dynamic-wind
|
||||
(lambda () (display "in "))
|
||||
(lambda ()
|
||||
(display "pre ")
|
||||
(display (call/cc out))
|
||||
#f)
|
||||
(lambda () (display "out "))))])
|
||||
(when v (v "post ")))
|
||||
|
||||
(let/ec k0
|
||||
(let/ec k1
|
||||
(dynamic-wind
|
||||
void
|
||||
(lambda () (k0 'cancel))
|
||||
(lambda () (k1 'cancel-canceled)))))
|
||||
|
||||
(let* ([x (make-parameter 0)]
|
||||
[l null]
|
||||
[add (lambda (a b)
|
||||
(set! l (append l (list (cons a b)))))])
|
||||
(let ([k (parameterize ([x 5])
|
||||
(dynamic-wind
|
||||
(lambda () (add 1 (x)))
|
||||
(lambda () (parameterize ([x 6])
|
||||
(let ([k+e (let/cc k (cons k void))])
|
||||
(add 2 (x))
|
||||
((cdr k+e))
|
||||
(car k+e))))
|
||||
(lambda () (add 3 (x)))))])
|
||||
(parameterize ([x 7])
|
||||
(let/cc esc
|
||||
(k (cons void esc)))))
|
||||
l)
|
||||
]}
|
11
collects/scribblings/reference/control.scrbl
Normal file
11
collects/scribblings/reference/control.scrbl
Normal file
|
@ -0,0 +1,11 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:control" #:style 'toc]{Control Flow}
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@include-section["exns.scrbl"]
|
||||
@include-section["cont.scrbl"]
|
||||
@include-section["cont-marks.scrbl"]
|
||||
@include-section["breaks.scrbl"]
|
|
@ -5,7 +5,7 @@
|
|||
@title[#:tag "mz:custodians"]{Custodians}
|
||||
|
||||
See @secref["mz:custodian-model"] for basic information on the PLT
|
||||
Scheme custodian parameter model.
|
||||
Scheme custodian model.
|
||||
|
||||
@defproc[(make-custodian [cust custodian? (current-custodian)]) custodian?]{
|
||||
|
||||
|
|
370
collects/scribblings/reference/evts.scrbl
Normal file
370
collects/scribblings/reference/evts.scrbl
Normal file
|
@ -0,0 +1,370 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "struct.ss" "scribble")]
|
||||
@require["mz.ss"]
|
||||
|
||||
@define[(ResultItself x)
|
||||
(make-element #f (list "The "
|
||||
(tech "synchronization result")
|
||||
" of " x " is " x " itself"))]
|
||||
|
||||
@title[#:tag "mz:sync"]{Events}
|
||||
|
||||
@index['("select")]{@index['("poll")]{A}} @deftech{synchronizable
|
||||
event} (or just @defterm{event} for short) works with the
|
||||
@scheme[sync] procedure to coordinate synchronization among
|
||||
threads. Certain kinds of objects double as events, including
|
||||
ports and threads. Other kinds of objects exist only for their
|
||||
use as events.
|
||||
|
||||
At an point in time, an event is either @defterm{ready} for
|
||||
synchronization, or it is not; depending on the kind of event and how
|
||||
it is used by other threads, an event can switch from not ready to
|
||||
ready (or back), at any time. If a thread synchronizes on an event
|
||||
when it is ready, then the event produces a particular
|
||||
@deftech{synchronization result}.
|
||||
|
||||
Synchronizing an event may affect the state of the event. For example,
|
||||
when synchronizing a semaphore, then the semaphore's internal count is
|
||||
decremented, just as with @scheme[semaphore-wait]. For most kinds of
|
||||
events, however (such as a port), synchronizing does not modify the
|
||||
event's state.
|
||||
|
||||
The following act as events in stand-alone MzScheme. An extension or
|
||||
embedding application can extend the set of primitive events --- in
|
||||
particular, an eventspace in MrEd is an event --- and new structure
|
||||
types can generate events (see @secref["mz:evt-structs"]).
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{@scheme[semaphore] --- a semaphore is ready when
|
||||
@scheme[semaphore-wait] (see @secref["mz:semaphore"]) would not
|
||||
block. @ResultItself{semaphore}.}
|
||||
|
||||
@item{@scheme[semaphore-peek] --- a semaphore-peek event returned by
|
||||
@scheme[semaphore-peek-evt] applied to @scheme[semaphore] (see
|
||||
@secref["mz:semaphore"]) is ready exactly when @scheme[semaphore] is
|
||||
ready. @ResultItself{semaphore-peek}.}
|
||||
|
||||
@item{@scheme[channel] --- a channel returned by @scheme[make-channel]
|
||||
is ready when @scheme[channel-get] would not block (see
|
||||
@secref["mz:channel"]). The channel's result as an event is the same as
|
||||
the @scheme[channel-get] result.}
|
||||
|
||||
@item{@scheme[channel-put] --- an event returned by
|
||||
@scheme[channel-put-evt] applied to @scheme[channel] is ready when
|
||||
@scheme[channel-put] would not block on @scheme[channel] (see
|
||||
@secref["mz:channel"]). @ResultItself{channel-put}.}
|
||||
|
||||
@item{@scheme[input-port] --- an input port is ready as an event when
|
||||
@scheme[read-byte] would not block. @ResultItself{input-port}.}
|
||||
|
||||
@item{@scheme[output-port] --- an output port is ready when
|
||||
@scheme[write-bytes-avail] would not block (see @secref["mz:write"]) or
|
||||
when the port contains buffered characters and
|
||||
@scheme[write-bytes-avail*] can flush part of the buffer (although
|
||||
@scheme[write-bytes-avail] might block). @ResultItself{output-port}.}
|
||||
|
||||
@item{@scheme[progress] --- an event produced by
|
||||
@scheme[port-progress-evt] applied to @scheme[input-port] is ready after
|
||||
any subsequent read from @scheme[input-port]. @ResultItself{progress}.}
|
||||
|
||||
@item{@scheme[tcp-listener] --- a TCP listener is ready when
|
||||
@scheme[tcp-accept] (see @secref["mz:tcp"]) would not block.
|
||||
@ResultItself{listener}.}
|
||||
|
||||
@item{@scheme[thd] --- a thread is ready when @scheme[thread-wait]
|
||||
(see @secref["mz:threadsync"]) would not block. @ResultItself{thread}.}
|
||||
|
||||
@item{@scheme[thread-dead] --- an event returned by
|
||||
@scheme[thread-dead-evt] (see @secref["mz:threadsync"]) applied to
|
||||
@scheme[thd] is ready when @scheme[thd] has terminated.
|
||||
@ResultItself{thread-dead}.}
|
||||
|
||||
@item{@scheme[thread-resume] --- an event returned by
|
||||
@scheme[thread-resume-evt] (see @secref["mz:threadsync"]) applied to
|
||||
@scheme[thd] is ready when @scheme[thd] subsequently resumes
|
||||
execution (if it was not already running). The event's result is
|
||||
@scheme[thd].}
|
||||
|
||||
@item{@scheme[thread-suspend] --- an event returned by
|
||||
@scheme[thread-suspend-evt] (see @secref["mz:threadsync"]) applied to
|
||||
@scheme[thd] is ready when @scheme[thd] subsequently suspends
|
||||
execution (if it was not already suspended). The event's result is
|
||||
@scheme[thd].}
|
||||
|
||||
@item{@scheme[alarm] --- an event returned by @scheme[alarm-evt] is
|
||||
ready after a particular date and time. @ResultItself{alarm}.}
|
||||
|
||||
@item{@scheme[subprocess] --- a subprocess is ready when
|
||||
@scheme[subprocess-wait] (see @secref["mz:subprocess"]) would not block.
|
||||
@ResultItself{subprocess}.}
|
||||
|
||||
@item{@scheme[will-executor] --- a will executor is ready when
|
||||
@scheme[will-execute] (see @secref["mz:willexecutor"]) would not block.
|
||||
@ResultItself{will-executor}.}
|
||||
|
||||
@item{@scheme[udp] --- an event returned by @scheme[udp-send-evt] or
|
||||
@scheme[udp-receive!-evt] (see @secref["mz:udp"]) is ready when a send or
|
||||
receive on the original socket would block, respectively. @ResultItself{udp}.}
|
||||
|
||||
@item{@scheme[choice] --- an event returned by @scheme[choice-evt] (see
|
||||
below) is ready when one or more of the @scheme[evt]s supplied to
|
||||
@scheme[chocie-evt] are ready. If the choice event is chosen, one of
|
||||
its ready @scheme[evt]s is chosen pseudo-randomly, and the result is the
|
||||
chosen @scheme[evt]'s result.}
|
||||
|
||||
@item{@scheme[wrap] --- an event returned by @scheme[wrap-evt]
|
||||
applied to @scheme[evt] and @scheme[proc] is ready when @scheme[evt] is
|
||||
ready. The event's result is obtained by a call to @scheme[proc] (with
|
||||
breaks disabled) on the result of @scheme[evt].}
|
||||
|
||||
@item{@scheme[handle] --- an event returned by @scheme[handle-evt]
|
||||
applied to @scheme[evt] and @scheme[proc] is ready when @scheme[evt] is
|
||||
ready. The event's result is obtained by a tail call to @scheme[proc] on
|
||||
the result of @scheme[evt].}
|
||||
|
||||
@item{@elemtag["mz:guard-evt"]{@scheme[guard]} --- an event returned by @scheme[guard-evt] applied
|
||||
to @scheme[thunk] generates a new event every time that @scheme[guard] is
|
||||
used with @scheme[sync] (or whenever it is part of a choice event
|
||||
used with @scheme[sync], etc.); the generated event is the result of
|
||||
calling @scheme[thunk] when the synchronization begins; if @scheme[thunk]
|
||||
returns a non-event, then @scheme[thunk]'s result is replaced with an
|
||||
event that is ready and whose result is @scheme[guard].}
|
||||
|
||||
@item{@elemtag["mz:nack-guard-evt"]{@scheme[nack-guard]} --- an event
|
||||
returned by @scheme[nack-guard-evt] applied to @scheme[proc]
|
||||
generates a new event every time that @scheme[nack-guard] is used
|
||||
with @scheme[sync] (or whenever it is part of a choice event used
|
||||
with @scheme[sync], etc.); the generated event is the result of
|
||||
calling @scheme[proc] with a NACK (``negative acknowledgment'') event
|
||||
when the synchronization begins; if @scheme[proc] returns a
|
||||
non-event, then @scheme[proc]'s result is replaced with an event that
|
||||
is ready and whose result is @scheme[nack-guard].
|
||||
|
||||
If the event from @scheme[proc] is not ultimately chosen as the
|
||||
unblocked event, then the NACK event supplied to @scheme[proc]
|
||||
becomes ready with a @|void-const| value. This NACK event becomes ready
|
||||
when the event is abandoned because some other event is chosen,
|
||||
because the synchronizing thread is dead, or because control escaped
|
||||
from the call to @scheme[sync] (even if @scheme[nack-guard]'s @scheme[proc]
|
||||
has not yet returned a value). If the event returned by @scheme[proc] is
|
||||
chosen, then the NACK event never becomes ready.}
|
||||
|
||||
@item{@elemtag["mz:poll-guard-evt"]{@scheme[poll-guard]} --- an event
|
||||
returned by @scheme[poll-guard-evt] applied to @scheme[proc]
|
||||
generates a new event every time that @scheme[poll-guard] is used
|
||||
with @scheme[sync] (or whenever it is part of a choice event used
|
||||
with @scheme[sync], etc.); the generated event is the result of
|
||||
calling @scheme[proc] with a boolean: @scheme[#t] if the event will
|
||||
be used for a poll, @scheme[#f] for a blocking synchronization.
|
||||
|
||||
If @scheme[#t] is supplied to @scheme[proc], if breaks are disabled, if
|
||||
the polling thread is not terminated, and if polling the resulting
|
||||
event produces a result, the event will certainly be chosen for its
|
||||
result.}
|
||||
|
||||
@item{@scheme[struct] --- a structure whose type has the
|
||||
@scheme[prop:evt] property identifies/generates an event through
|
||||
the property; see @secref["mz:evt-structs"] for further information.}
|
||||
|
||||
@item{@scheme[always-evt] --- a constant event that is always
|
||||
ready. @ResultItself{@scheme[always-evt]}.}
|
||||
|
||||
@item{@scheme[never-evt] --- a constant event that is never ready.}
|
||||
|
||||
@item{@elemtag["mz:system-idle-evt"]{@scheme[idle]} --- an event
|
||||
produced by @scheme[system-idle-evt] is ready when, if this event
|
||||
were replaced by @scheme[never-evt], no thread in the system would
|
||||
be available to run. In other words, all threads must be suspended
|
||||
or blocked on events with timeouts that have not yet expired. The
|
||||
event's result is @|void-const|.}
|
||||
|
||||
}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
@defproc[(sync [evt evt?] ...+) any]{
|
||||
|
||||
Blocks as long as none of the @tech{synchronizable events}
|
||||
@scheme[evt]s are ready, as defined above.
|
||||
|
||||
When at least one @scheme[evt] is ready, its @tech{synchronization
|
||||
result} (often @scheme[evt] itself) is returned. If multiple
|
||||
@scheme[evt]s are ready, one of the @scheme[evt]s is chosen
|
||||
pseudo-randomly for the result; the
|
||||
@scheme[current-evt-pseudo-random-generator] parameter sets the
|
||||
random-number generator that controls this choice.}
|
||||
|
||||
|
||||
@defproc[(sync/timeout [timeout-secs (or/c nonnegative-number? false/c)]
|
||||
[evt evt?] ...+)
|
||||
any]{
|
||||
|
||||
Like @scheme[sync], but returns @scheme[#f] if @scheme[timeout-secs]
|
||||
is not @scheme[#f] and if @scheme[timeout-secs] seconds pass without a
|
||||
successful synchronization.
|
||||
|
||||
If @scheme[timeout-secs] is @scheme[0], each @scheme[evt] is checked
|
||||
at least once, so a @scheme[timeout-secs] value of @scheme[0] can be
|
||||
used for polling.
|
||||
|
||||
See also @scheme[alarm-evt] for an alternative timeout mechanism.}
|
||||
|
||||
|
||||
@defproc[(sync/enable-break [evt evt?] ...+) any]{
|
||||
|
||||
Like @scheme[sync], but breaking is enabled (see
|
||||
@secref["mz:breakhandler"]) while waiting on the @scheme[evt]s. If
|
||||
breaking is disabled when @scheme[sync/enable-break] is called, then
|
||||
either all @scheme[evt]s remain unchosen or the @scheme[exn:break]
|
||||
exception is raised, but not both.}
|
||||
|
||||
|
||||
@defproc[(sync/timeout/enable-break [timeout-secs (or/c nonnegative-number? false/c)]
|
||||
[evt evt?] ...+)
|
||||
any]{
|
||||
|
||||
Like @scheme[sync/enable-break], but with a timeout in seconds (or
|
||||
@scheme[#f]), as for @scheme[sync/timeout].}
|
||||
|
||||
|
||||
@defproc[(choice-evt [evt evt?] ...) evt?]{
|
||||
|
||||
Creates and returns a single event that combines the
|
||||
@scheme[evt]s. Supplying the result to @scheme[sync] is the same as
|
||||
supplying each @scheme[evt] to the same call.}
|
||||
|
||||
|
||||
@defproc[(wrap-evt [evt (and/c evt? (not/c handle-evt?))]
|
||||
[wrap (any/c . -> . any)])
|
||||
evt?]{
|
||||
|
||||
Creates an event that is in a ready when @scheme[evt] is ready, but
|
||||
whose result is determined by applying @scheme[wrap] to the result of
|
||||
@scheme[evt]. The call to @scheme[wrap] is
|
||||
@scheme[parameterize-break]ed to disable breaks initially. The
|
||||
@scheme[evt] cannot be an event created by @scheme[handle-evt] or any
|
||||
combination of @scheme[choice-evt] involving an event from
|
||||
@scheme[handle-evt].}
|
||||
|
||||
@defproc[(handle-evt [evt (and/c evt? (not/c handle-evt?))]
|
||||
[handle (any/c . -> . any)])
|
||||
evt?]{
|
||||
|
||||
Like @scheme[wrap], except that @scheme[handle] is called in tail
|
||||
position with respect to the synchronization request, and without
|
||||
breaks explicitly disabled.}
|
||||
|
||||
@defproc[(guard-evt [generator (-> evt?)]) evt?]{
|
||||
|
||||
Creates a value that behaves as an event, but that is actually an
|
||||
event generator. For details, see @elemref["mz:guard-evt"]{the
|
||||
overview}.}
|
||||
|
||||
@defproc[(nack-guard-evt [generator (evt? . -> . evt?)]) evt?]{
|
||||
|
||||
Creates a value that behaves as an event, but that is actually an
|
||||
event generator; the generator procedure receives an event that
|
||||
becomes ready with a @|void-const| value if the generated event was
|
||||
not ultimately chosen. For details, see
|
||||
@elemref["mz:nack-guard-evt"]{the overview}.}
|
||||
|
||||
@defproc[(poll-guard-evt [generator (boolean? . -> . evt?)]) evt?]{
|
||||
|
||||
Creates a value that behaves as an event, but that is actually an
|
||||
event generator; the generator procedure receives a boolean indicating
|
||||
whether the event is used for polling. For details, see
|
||||
@elemref["mz:poll-guard-evt"]{the overview}.}
|
||||
|
||||
@defthing[always-evt evt?]{A constant event that is always ready, with
|
||||
itself as its result.}
|
||||
|
||||
@defthing[never-evt evt?]{A constant event that is never ready.}
|
||||
|
||||
|
||||
@defproc[(system-idle-evt) evt?]{Returns an event that is ready when
|
||||
the system is otherwise idle; see @elemref["mz:system-idle-evt"]{the
|
||||
overview} for more information. The result of the
|
||||
@scheme[system-idle-evt] procedure is always the same event.}
|
||||
|
||||
|
||||
@defproc[(alarm-evt [msecs nonnegative-number?]) evt]{
|
||||
|
||||
Returns a synchronizable event that is not ready when
|
||||
@scheme[(current-inexact-milliseconds)] would return a value that is
|
||||
less than @scheme[msecs], and it is ready when
|
||||
@scheme[(current-inexact-milliseconds)] would return a value that is
|
||||
more than @scheme[msecs].}
|
||||
|
||||
|
||||
@defproc[(evt? [v any/c]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[v] is a @tech{synchronizable event},
|
||||
@scheme[#f] otherwise.}
|
||||
|
||||
@defproc[(handle-evt? [evt evt?]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[evt] was created by @scheme[handle-evt]
|
||||
or by @scheme[choice-evt] applied to another event for which
|
||||
@scheme[handle-evt?] produces @scheme[#t]. Such events are illegal as
|
||||
an argument to @scheme[handle-evt] or @scheme[wrap-evt], because they
|
||||
cannot be wrapped further. For any other event, @scheme[handle-evt?]
|
||||
produces @scheme[#f], and the event is a legal argument to
|
||||
@scheme[handle-evt] or @scheme[wrap-evt] for further wrapping.}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@defthing[prop:evt struct-type-property?]{
|
||||
|
||||
A @tech{structure type property} that identifies structure types whose
|
||||
instances can serve as synchronizable events. The property value can
|
||||
be any of the following:
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{An event @scheme[evt]: In this case, using the structure as an
|
||||
event is equivalent to using @scheme[evt].}
|
||||
|
||||
@item{A procedure @scheme[proc] of one argument: In this case, the
|
||||
structure is similar to an event generated
|
||||
by @scheme[guard-evt], except that the would-be guard
|
||||
procedure @scheme[proc] receives the structure as an argument, instead
|
||||
of no arguments.}
|
||||
|
||||
@item{An exact, non-negative integer between @scheme[0] (inclusive)
|
||||
and the number of non-automatic fields in the structure type
|
||||
(exclusive, not counting supertype fields): The integer identifies a
|
||||
field in the structure, and the field must be designated as
|
||||
immutable. If the field contains an object or an event-generating
|
||||
procedure of one argument, the event or procedure is used as
|
||||
above. Otherwise, the structure acts as an event that is never
|
||||
ready.}
|
||||
|
||||
}
|
||||
|
||||
Instances of a structure type with the @scheme[prop:input-port] or
|
||||
@scheme[prop:output-port] property (see @secref["mz:portstructs"]) are
|
||||
also synchronizable by virtue of being a port. If the structure type
|
||||
has more than one of @scheme[prop:evt], @scheme[prop:input-port], and
|
||||
@scheme[prop:output-port], then the @scheme[prop:evt] value (if any)
|
||||
takes precedence for determing the instance's behavior as an event,
|
||||
and the @scheme[prop:input-port] property takes precedence over
|
||||
@scheme[prop:output-port] for synchronization.
|
||||
|
||||
@examples[
|
||||
(define-struct wt ([base #:immutable] val)
|
||||
#:property prop:evt (struct-field-index base))
|
||||
|
||||
(define sema (make-semaphore))
|
||||
(sync/timeout 0 (make-wt sema #f))
|
||||
(semaphore-post sema)
|
||||
(sync/timeout 0 (make-wt sema #f))
|
||||
(semaphore-post sema)
|
||||
(sync/timeout 0 (make-wt (lambda (self) (wt-val self)) sema))
|
||||
(semaphore-post sema)
|
||||
(define my-wt (make-wt (lambda (self) (wrap-evt
|
||||
(wt-val self)
|
||||
(lambda (x) self)))
|
||||
sema))
|
||||
(sync/timeout 0 my-wt)
|
||||
(sync/timeout 0 my-wt)
|
||||
]}
|
|
@ -48,7 +48,7 @@ expression that evaluation simplifies no further, such as the number
|
|||
@scheme[2].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sub-expression Evaluation and Continuations}
|
||||
@section[#:tag "mz:cont-model"]{Sub-expression Evaluation and Continuations}
|
||||
|
||||
Some simplifications require more than one step. For example:
|
||||
|
||||
|
@ -581,7 +581,7 @@ re-declared, each re-declaration of the module is immediately
|
|||
@tech{instantiate}d in the same @tech{phase}s.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Continuation Frames and Marks}
|
||||
@section[#:tag "mz:mark-model"]{Continuation Frames and Marks}
|
||||
|
||||
Every continuation @scheme[_C] can be partitioned into
|
||||
@deftech{continuation frames} @frame[1], @frame[2], ..., @frame["n"]
|
||||
|
@ -600,7 +600,7 @@ for a ``stack trace'' to be used when an exception is raised, or
|
|||
to implement dynamic scope.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Prompts and Delimited Continuations}
|
||||
@section[#:tag "mz:prompt-model"]{Prompts, Delimited Continuations, and Barriers}
|
||||
|
||||
A @deftech{prompt} is a special kind of continuation frame that is
|
||||
annotated with a specific @deftech{prompt-tag} (essentially a
|
||||
|
@ -615,6 +615,22 @@ a particular tag, or replace the continuation to the nearest enclosing
|
|||
prompt with another one. When a delimited continuation is captured,
|
||||
the marks associated with the relevant frames are also captured.
|
||||
|
||||
A @deftech{continuation barrier} is another kind of continuation frame
|
||||
that prohibits certain replacements of the current continuation with
|
||||
another. Specifically, while an abort is allowed to remove a portion
|
||||
of the continuation containing a prompt, the continuation can be
|
||||
replaced by another only when the replacement also includes the
|
||||
continuation barrier. Certain operations install barriers
|
||||
automatically; in particular, when an exception handler is called, a
|
||||
continuation barrier prohibits the continuation of the handler from
|
||||
capturing the continuation past the exception point.
|
||||
|
||||
A @deftech{escape continuation} is essentially a derived concept. It
|
||||
combines a prompt for escape purposes with a continuation for
|
||||
mark-gathering purposes. as the name implies, escape continuations are
|
||||
used only to abort to the point of capture, which means that
|
||||
escape-continuation aborts can cross continuation barriers.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:thread-model"]{Threads}
|
||||
|
||||
|
|
156
collects/scribblings/reference/parameters.scrbl
Normal file
156
collects/scribblings/reference/parameters.scrbl
Normal file
|
@ -0,0 +1,156 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:parameters"]{Parameters}
|
||||
|
||||
See @secref["mz:parameter-model"] for basic information on the
|
||||
parameter model. Parameters correspond to @defterm{preserved thread
|
||||
fluids} in \first{Scsh} @cite[#:key "cite:thread-fluids" #:title
|
||||
"Processes vs. User-Level Threads in Scsh" #:author "Martin Gasbichler
|
||||
and Michael Sperber" #:date 2002 #:location "Scheme Workshop"].
|
||||
|
||||
To parameterize code in a thread- and continuation-friendly manner,
|
||||
use @scheme[parameterize]. The @scheme[parameterize] form introduces a
|
||||
fresh @tech{thread cell} for the dynamic extent of its body
|
||||
expressions.
|
||||
|
||||
When a new thread is created, the @tech{parameterization} for the new
|
||||
thread's initial continuation is the @tech{parameterization} of the
|
||||
creator thread. Since each parameter's @tech{thread cell} is
|
||||
@tech{preserved}, the new thread ``inherits'' the parameter values of
|
||||
its creating thread. When a continuation is moved from one thread to
|
||||
another, settings introduced with @scheme[parameterize] effectively
|
||||
move with the continuation.
|
||||
|
||||
In contrast, direct assignment to a parameter (by calling the
|
||||
parameter procedure with a value) changes the value in a thread cell,
|
||||
and therefore changes the setting only for the current
|
||||
thread. Consequently, as far as the memory manager is concerned, the
|
||||
value originally associated with a parameter through
|
||||
@scheme[parameterize] remains reachable as long the continuation is
|
||||
reachable, even if the parameter is mutated.
|
||||
|
||||
@defproc[(make-parameter [v any/c]
|
||||
[guard (or/c (any/c . -> . any) false/c) #f])
|
||||
parameter?]{
|
||||
|
||||
Returns a new parameter procedure. The value of the parameter is
|
||||
initialized to @scheme[v] in all threads. If @scheme[guard] is
|
||||
supplied, it is used as the parameter's guard procedure. A guard
|
||||
procedure takes one argument. Whenever the parameter procedure is
|
||||
applied to an argument, the argument is passed on to the guard
|
||||
procedure. The result returned by the guard procedure is used as the
|
||||
new parameter value. A guard procedure can raise an exception to
|
||||
reject a change to the parameter's value. The @scheme[guard] is not
|
||||
applied to the initial @scheme[v].}
|
||||
|
||||
@defform[(parameterize ((parameter-expr value-expr) ...)
|
||||
body ...+)]{
|
||||
|
||||
The result of a @scheme[parameterize] expression is the result of the
|
||||
last @scheme[body]. The @scheme[parameter-expr]s determine the
|
||||
parameters to set, and the @scheme[value-expr]s determine the
|
||||
corresponding values to install while evaluating the
|
||||
@scheme[body-expr]s. All of the @scheme[parameter-expr]s are evaluated
|
||||
first (and checked with @scheme[parameter?]), then all
|
||||
@scheme[value-expr]s are evaluated, and then the parameters are bound
|
||||
in the continuation to preserved thread cells that contain the values
|
||||
of the @scheme[value-expr]s. The last @scheme[body-expr] is in tail
|
||||
position with respect to the entire @scheme[parameterize] form.
|
||||
|
||||
Outside the dynamic extent of a @scheme[parameterize] expression,
|
||||
parameters remain bound to other thread cells. Effectively, therefore,
|
||||
old parameters settings are restored as control exits the
|
||||
@scheme[parameterize] expression.
|
||||
|
||||
If a continuation is captured during the evaluation of
|
||||
@scheme[parameterize], invoking the continuation effectively
|
||||
re-introduces the @tech{parameterization}, since a parameterization is
|
||||
associated to a continuation via a continuation mark (see
|
||||
@secref["mz:contmarks"]) using a private key.}
|
||||
|
||||
@examples[
|
||||
(parameterize ([exit-handler (lambda (x) 'no-exit)])
|
||||
(exit))
|
||||
|
||||
(define p1 (make-parameter 1))
|
||||
(define p2 (make-parameter 2))
|
||||
(parameterize ([p1 3]
|
||||
[p2 (p1)])
|
||||
(cons (p1) (p2)))
|
||||
|
||||
(let ([k (let/cc out
|
||||
(parameterize ([p1 2])
|
||||
(p1 3)
|
||||
(cons (let/cc k
|
||||
(out k))
|
||||
(p1))))])
|
||||
(if (procedure? k)
|
||||
(k (p1))
|
||||
k))
|
||||
|
||||
(define ch (make-channel))
|
||||
(parameterize ([p1 0])
|
||||
(thread (lambda ()
|
||||
(channel-put ch (cons (p1) (p2))))))
|
||||
(channel-get ch)
|
||||
|
||||
(define k-ch (make-channel))
|
||||
(define (send-k)
|
||||
(parameterize ([p1 0])
|
||||
(thread (lambda ()
|
||||
(let/ec esc
|
||||
(channel-put ch
|
||||
((let/cc k
|
||||
(channel-put k-ch k)
|
||||
(esc)))))))))
|
||||
(send-k)
|
||||
(thread (lambda () ((channel-get k-ch)
|
||||
(let ([v (p1)])
|
||||
(lambda () v)))))
|
||||
(channel-get ch)
|
||||
(send-k)
|
||||
(thread (lambda () ((channel-get k-ch) p1)))
|
||||
(channel-get ch)
|
||||
]
|
||||
|
||||
@defform[(parameterize* ((parameter-expr value-expr) ...)
|
||||
body ...+)]{
|
||||
|
||||
Analogous to @scheme[let*] compared to @scheme[let], @scheme[parameterize*]
|
||||
is the same as a nested series of single-parameter @scheme[parameterize]
|
||||
forms.}
|
||||
|
||||
|
||||
@defproc[(make-derived-parameter [v any/c]
|
||||
[guard (any/c . -> . any)])
|
||||
parameter?]{
|
||||
|
||||
Returns a parameter procedure that sets or retrieves the same value as
|
||||
@scheme[parameter], but with the additional guard @scheme[guard]
|
||||
applied (before any guard associated with @scheme[parameter]).}
|
||||
|
||||
@defproc[(parameter? [v any/c]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[v] is a parameter procedure,
|
||||
@scheme[#f] otherwise.}
|
||||
|
||||
@defproc[(parameter-procedure=? [a parameter?][b parameter?]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if the parameter procedures @scheme[a] and
|
||||
@scheme[b] always modify the same parameter with the same guards,
|
||||
@scheme[#f] otherwise.}
|
||||
|
||||
|
||||
@defproc[(current-parameterization) parameterization?]{Returns the
|
||||
current continuation's @tech{parameterization}.}
|
||||
|
||||
@defproc[(call-with-parameterization [parameterization parameterization?]
|
||||
[thunk (-> any)])
|
||||
any]{
|
||||
Calls @scheme[thunk] (via a tail call) with @scheme[parameterization]
|
||||
as the current @tech{parameterization}.}
|
||||
|
||||
@defproc[(parameterization? [v any/c]) boolean?]{
|
||||
Returns @scheme[#t] if @scheme[v] is a @tech{parameterization}
|
||||
returned by @scheme[current-parameterization], @scheme[#f] otherwise.}
|
|
@ -146,3 +146,98 @@ obtains its result frmo @scheme[plain-proc].
|
|||
|
||||
@defstruct[arity-at-least ([value nonnegative-exact-integer?])]{
|
||||
This structure type is used for the result of @scheme[procedure-arity].}
|
||||
|
||||
@defthing[prop:procedure struct-type-property?]{
|
||||
|
||||
A @tech{structure type property} to indentify structure types whose
|
||||
instances can be applied as procedures. In particular, when
|
||||
@scheme[procedure?] is applied to the instance, the result will be
|
||||
@scheme[#t], and when an instance is used in the function position of
|
||||
an application expression, a procedure is extracted from the instance
|
||||
and used to complete the procedure call.
|
||||
|
||||
If the @scheme[prop:procedure] property value is an integer, it
|
||||
designates a field within the structure that should contain a
|
||||
procedure. The integer must be between @scheme[0] (inclusive) and the
|
||||
number of non-automatic fields in the structure type (exclusive, not
|
||||
counting supertype fields). The designated field must also be
|
||||
specified as immutable, so that after an instance of the structure is
|
||||
created, its procedure cannot be changed. (Otherwise, the arity and
|
||||
name of the instance could change, and such mutations are generally
|
||||
not allowed for procedures.) When the instance is used as the
|
||||
procedure in an application expression, the value of the designated
|
||||
field in the instance is used to complete the procedure call. (This
|
||||
procedure can be another structure that acts as a procedure; the
|
||||
immutability of procedure fields disallows cycles in the procedure
|
||||
graph, so that the procedure call will eventually continue with a
|
||||
non-structure procedure.) That procedure receives all of the arguments
|
||||
from the application expression. The procedure's name (see
|
||||
@secref["mz:infernames"]) and arity (see @secref["mz:arity"]) are also
|
||||
used for the name and arity of the structure. If the value in the
|
||||
designated field is not a procedure, then the instance behaves like
|
||||
@scheme[(case-lambda)] (i.e., a procedure which does not accept any
|
||||
number of arguments).
|
||||
|
||||
Providing an integer @scheme[proc-spec] argument to
|
||||
@scheme[make-struct-type] is the same as both supplying the value with
|
||||
the @scheme[prop:procedure] property and designating the field as
|
||||
immutable (so that a property binding or immutable designation is
|
||||
redundant and disallowed).
|
||||
|
||||
@examples[
|
||||
(define-struct annotated-proc ([base #:immutable] note)
|
||||
#:property prop:procedure (struct-field-index base))
|
||||
(define plus1 (make-annotated-proc
|
||||
(lambda (x) (+ x 1))
|
||||
"adds 1 to its argument"))
|
||||
(procedure? plus1)
|
||||
(annotated-proc? plus1)
|
||||
(plus1 10)
|
||||
(annotated-proc-note plus1)
|
||||
]
|
||||
|
||||
When the @scheme[prop:procedure] value is a procedure, it should
|
||||
accept at least one argument. When an instance of the structure is
|
||||
used in an application expression, the property-value procedure is
|
||||
called with the instance as the first argument. The remaining
|
||||
arguments to the property-value procedure are the arguments from the
|
||||
application expression. Thus, if the application expression contained
|
||||
five arguments, the property-value procedure is called with six
|
||||
arguments. The name of the instance (see @secref["mz:infernames"]) is
|
||||
unaffected by the property-value procedure, but the instance's arity
|
||||
is determined by subtracting one from every possible argument count of
|
||||
the property-value procedure. If the property-value procedure cannot
|
||||
accept at least one argument, then the instance behaves like
|
||||
@scheme[(case-lambda)].
|
||||
|
||||
Providing a procedure @scheme[proc-spec] argument to
|
||||
@scheme[make-struct-type] is the same as supplying the value with the
|
||||
@scheme[prop:procedure] property (so that a specific property binding
|
||||
is disallowed).
|
||||
|
||||
@examples[
|
||||
(define-struct fish (weight color)
|
||||
#:property
|
||||
prop:procedure
|
||||
(lambda (f n) (set-fish-weight! f (+ n (fish-weight f)))))
|
||||
(define wanda (make-fish 12 'red))
|
||||
(fish? wanda)
|
||||
(procedure? wanda)
|
||||
(fish-weight wanda)
|
||||
(for-each wanda '(1 2 3))
|
||||
(fish-weight wanda)
|
||||
]
|
||||
|
||||
If a structure type generates procedure instances, then subtypes of
|
||||
the type also generate procedure instances. The instances behave the
|
||||
same as instances of the original type. When a @scheme[prop:procedure]
|
||||
property or non-@scheme[#f] @scheme[proc-spec] is supplied to
|
||||
@scheme[make-struct-type] with a supertype that already behaves as a
|
||||
procedure, the @exnraise[exn:fail:contract].}
|
||||
|
||||
@defproc[(procedure-struct-type? [type struct-type?]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if instances of the structure type represented by
|
||||
@scheme[type] are procedures (according to @scheme[procedure?]),
|
||||
@scheme[#f] otherwise.}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ language.
|
|||
|
||||
@;------------------------------------------------------------------------
|
||||
@include-section["regexps.scrbl"]
|
||||
@include-section["exns.scrbl"]
|
||||
@include-section["threads.scrbl"]
|
||||
@include-section["control.scrbl"]
|
||||
@include-section["concurrency.scrbl"]
|
||||
@include-section["custodians.scrbl"]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
|
88
collects/scribblings/reference/semaphores.scrbl
Normal file
88
collects/scribblings/reference/semaphores.scrbl
Normal file
|
@ -0,0 +1,88 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "bnf.ss" "scribble")]
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:semaphore"]{Semaphores}
|
||||
|
||||
A @deftech{semaphore} has an internal counter; when this counter is
|
||||
zero, the semaphore can block a thread's execution (through
|
||||
@scheme[semaphore-wait]) until another thread increments the counter
|
||||
(using @scheme[semaphore-post]). The maximum value for a semaphore's
|
||||
internal counter is platform-specific, but always at least
|
||||
@scheme[10000].
|
||||
|
||||
A semaphore's counter is updated in a single-threaded manner, so that
|
||||
semaphores can be used for reliable synchronization. Semaphore waiting
|
||||
is @defterm{fair}: if a thread is blocked on a semaphore and the
|
||||
semaphore's internal value is non-zero infinitely often, then the
|
||||
thread is eventually unblocked.
|
||||
|
||||
In addition to its use with semaphore-specific procedures, semaphores
|
||||
can be used as events; see @secref["mz:sync"].
|
||||
|
||||
@defproc[(make-semaphore [init non-negative-exact-integer? 0]) semaphore?]{
|
||||
|
||||
Creates and returns a new semaphore with the counter initially set to
|
||||
@scheme[init]. If @scheme[init-k] is larger than a semaphore's maximum
|
||||
internal counter value, the @exnraise[exn:fail].}
|
||||
|
||||
|
||||
@defproc[(semaphore? [v any/c]) boolean?]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[v] is a semaphore created by
|
||||
@scheme[make-semaphore], @scheme[#f] otherwise.}
|
||||
|
||||
|
||||
@defproc[(semaphore-post [sema semaphore?]) void?]{Increments the
|
||||
semaphore's internal counter and returns @|void-const|. If the
|
||||
semaphore's internal counter has already reached its maximum value,
|
||||
the @exnraise[exn:fail].}
|
||||
|
||||
@defproc[(semaphore-wait [sema semaphore?]) void?]{Blocks until the
|
||||
internal counter for semaphore @scheme[sema] is non-zero. When the
|
||||
counter is non-zero, it is decremented and @scheme[semaphore-wait]
|
||||
returns @|void-const|.}
|
||||
|
||||
@defproc[(semaphore-try-wait? [sema semaphore?]) boolean?]{Like
|
||||
@scheme[semaphore-wait], but @scheme[semaphore-try-wait?] never blocks
|
||||
execution. If @scheme[sema]'s internal counter is zero,
|
||||
@scheme[semaphore-try-wait?] returns @scheme[#f] immediately without
|
||||
decrementing the counter. If @scheme[sema]'s counter is positive, it
|
||||
is decremented and @scheme[#t] is returned.}
|
||||
|
||||
@defproc[(semaphore-wait/enable-break [sema semaphore?]) void?]{Like
|
||||
@scheme[semaphore-wait], but breaking is enabled (see
|
||||
@secref["mz:breakhandler"]) while waiting on @scheme[sema]. If
|
||||
breaking is disabled when @scheme[semaphore-wait/enable-break] is
|
||||
called, then either the semaphore's counter is decremented or the
|
||||
@scheme[exn:break] exception is raised, but not both.}
|
||||
|
||||
@defproc[(semaphore-peek-evt [sema semaphore?]) evt?]{Creates and
|
||||
returns a new synchronizable event (for use with @scheme[sync], for
|
||||
example) that is ready when @scheme[sema] is ready, but synchronizing
|
||||
the event does not decrement @scheme[sema]'s internal count.}
|
||||
|
||||
@defproc[(call-with-semaphore [sema semaphore?]
|
||||
[proc procedure?]
|
||||
[try-fail-thunk (or/c (-> any) false/c) #f]
|
||||
[arg any/c] ...) any]{
|
||||
|
||||
Waits on @scheme[sema] using @scheme[semaphore-wait], calls
|
||||
@scheme[proc] with all @scheme[arg]s, and then posts to
|
||||
@scheme[sema]. A continuation barrier blocks full continuation jumps
|
||||
into or out of @scheme[proc] (see @secref["mz:continuations"]), but
|
||||
escape jumps are allowed, and @scheme[sema] is posted on escape. If
|
||||
@scheme[try-fail-thunk] is provided and is not @scheme[#f], then
|
||||
@scheme[semaphore-try-wait?] is called on @scheme[sema] instead of
|
||||
@scheme[semaphore-wait], and @scheme[try-fail-thunk] is called if the
|
||||
wait fails.}
|
||||
|
||||
@defproc[(call-with-semaphore/enable-break [sema semaphore?]
|
||||
[proc procedure?]
|
||||
[try-fail-thunk (or/c (-> any) false/c) #f]
|
||||
[arg any/c] ...) any]{
|
||||
Like @scheme[call-with-semaphore], except that
|
||||
@scheme[semaphore-wait/enable-break] is used with @scheme[sema] in
|
||||
non-try mode. When @scheme[try-fail-thunk] is provided and not
|
||||
@scheme[#f], then breaks are enabled around the use of
|
||||
@scheme[semaphore-try-wait?] on @scheme[sema].}
|
|
@ -190,12 +190,12 @@ The result of @scheme[make-struct-type] is five values:
|
|||
]}
|
||||
|
||||
@defproc[(make-struct-field-accessor [accessor-proc struct-accessot-procedure?]
|
||||
[field-pos-k exact-nonnegative-integer?]
|
||||
[field-pos exact-nonnegative-integer?]
|
||||
[field-name symbol?])
|
||||
procedure?]{
|
||||
|
||||
Returns a field accessor that is equivalent to @scheme[(lambda (s)
|
||||
(accessor-proc s field-pos-k))]. The @scheme[accessor-proc] must be
|
||||
(accessor-proc s field-pos))]. The @scheme[accessor-proc] must be
|
||||
an @tech{accessor} returned by @scheme[make-struct-type]. The name of the
|
||||
resulting procedure for debugging purposes is derived from
|
||||
@scheme[field-name] and the name of @scheme[accessor-proc]'s
|
||||
|
@ -204,12 +204,12 @@ structure type.
|
|||
For examples, see @scheme[make-struct-type].}
|
||||
|
||||
@defproc[(make-struct-field-mutator [mutator-proc struct-mutator-procedure?]
|
||||
[field-pos-k exact-nonnegative-integer?]
|
||||
[field-pos exact-nonnegative-integer?]
|
||||
[field-name symbol?])
|
||||
procedure?]{
|
||||
|
||||
Returns a field mutator that is equivalent to @scheme[(lambda (s v)
|
||||
(mutator-proc s field-pos-k v))]. The @scheme[mutator-proc] must be
|
||||
(mutator-proc s field-pos v))]. The @scheme[mutator-proc] must be
|
||||
a @tech{mutator} returned by @scheme[make-struct-type]. The name of the
|
||||
resulting procedure for debugging purposes is derived from
|
||||
@scheme[field-name] and the name of @scheme[mutator-proc]'s
|
||||
|
@ -221,7 +221,7 @@ For examples, see @scheme[make-struct-type].}
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:structprops"]{Structure Type Properties}
|
||||
|
||||
A @index['("structure type properties")]{@defterm{structure type
|
||||
A @index['("structure type properties")]{@deftech{structure type
|
||||
property}} allows per-type information to be associated with a
|
||||
structure type (as opposed to per-instance information associated
|
||||
with a structure value). A property value is associated with a
|
||||
|
|
27
collects/scribblings/reference/sync.scrbl
Normal file
27
collects/scribblings/reference/sync.scrbl
Normal file
|
@ -0,0 +1,27 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:all-sync" #:style 'toc]{Synchronization}
|
||||
|
||||
Scheme's synchronization toolbox spans three layers:
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{@tech{synchronizable events} --- a general framework for
|
||||
synchronization;}
|
||||
|
||||
@item{@tech{channels} --- a primitive that can be used, in principle,
|
||||
to build most other kinds of synchronizable events (except the ones
|
||||
that compose events); and}
|
||||
|
||||
@item{@tech{semaphores} --- a simple and especially cheap primitive
|
||||
for synchronization.}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@include-section["evts.scrbl"]
|
||||
@include-section["channels.scrbl"]
|
||||
@include-section["semaphores.scrbl"]
|
|
@ -643,11 +643,21 @@ corresponding value from @scheme[expr] in the same way as for
|
|||
@section[#:tag "mz:wcm"]{Continuation Marks: @scheme[with-continuation-mark]}
|
||||
|
||||
@defform[(with-continuation-mark key-expr val-expr result-expr)]{
|
||||
Evaluates @scheme[key-expr] and @scheme[val-expr] in order to obtain a key and
|
||||
value, respectively. The key and value are attached as a mark to the
|
||||
current continuation frame (see @secref["mz:contmarks"]), and then
|
||||
@scheme[result-expr] is evaluated in tail position.
|
||||
}
|
||||
|
||||
The @scheme[key-expr], @scheme[mark-expr], and @scheme[result-expr]
|
||||
expressions are evaluated in order. After @scheme[key-expr] is
|
||||
evaluated to obtain a key and @scheme[mark-expr] is evaluated to
|
||||
obtain a mark, the key is mapped to the mark in the current
|
||||
continuation's initial frame. If the frame already has a mark for the
|
||||
key, it is replaced. Finally, the @scheme[result-expr] is evaluated;
|
||||
the continuation for evaluating @scheme[result-expr] is the
|
||||
continuation of the @scheme[with-continuation-mark] expression (so the
|
||||
result of the @scheme[resultbody-expr] is the result of the
|
||||
@scheme[with-continuation-mark] expression, and @scheme[result-expr]
|
||||
is in tail position for the @scheme[with-continuation-mark]
|
||||
expression).
|
||||
|
||||
@moreref["mz:contmarks"]{continuation marks}}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Syntax Quoting: @scheme[quote-syntax]}
|
||||
|
|
93
collects/scribblings/reference/thread-cells.scrbl
Normal file
93
collects/scribblings/reference/thread-cells.scrbl
Normal file
|
@ -0,0 +1,93 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:threadcells"]{Thread Cells}
|
||||
|
||||
A @deftech{thread cell} contains a thread-specific value; that is, it
|
||||
contains a specific value for each thread, but it may contain
|
||||
different values for different threads. A thread cell is created with
|
||||
a default value that is used for all existing threads. When the cell's
|
||||
content is changed with @scheme[thread-cell-set!], the cell's value
|
||||
changes only for the current thread. Similarly,
|
||||
@scheme[thread-cell-ref] obtains the value of the cell that is
|
||||
specific to the current thread.
|
||||
|
||||
A thread cell's value can be @deftech{preserved}, which means that
|
||||
when a new thread is created, the cell's initial value for the new
|
||||
thread is the same as the creating thread's current value. If a thread
|
||||
cell is non-preserved, then the cell's initial value for a newly
|
||||
created thread is the default value (which was supplied when the cell
|
||||
was created).
|
||||
|
||||
Within the current thread, the current values of all preserved threads
|
||||
cells can be captured through
|
||||
@scheme[current-preserved-thread-cell-values]. The captured set of
|
||||
values can be imperatively installed into the current thread through
|
||||
another call to @scheme[current-preserved-thread-cell-values]. The
|
||||
capturing and restoring threads can be different.
|
||||
|
||||
@defproc[(make-thread-cell [v any/c][preserved? any/c #f]) thread-cell?]{
|
||||
|
||||
Creates and returns a new thread cell. Initially, @scheme[v] is the
|
||||
cell's value for all threads. If @scheme[preserved?] is true, then the
|
||||
cell's initial value for a newly created threads is the creating
|
||||
thread's value for the cell, otherwise the cell's value is initially
|
||||
@scheme[v] in all future threads.}
|
||||
|
||||
|
||||
@defproc[(thread-cell? [v any/c]) boolean?]{
|
||||
Returns @scheme[#t] if @scheme[v] is a thread cell created by
|
||||
@scheme[make-thread-cell], @scheme[#f] otherwise.}
|
||||
|
||||
|
||||
@defproc[(thread-cell-ref [cell thread-cell?]) any]{Returns the
|
||||
current value of @scheme[cell] for the current thread.}
|
||||
|
||||
@defproc[(thread-cell-set! [cell thread-cell?][v any/c]) any]{Sets the
|
||||
value in @scheme[cell] to @scheme[v] for the current thread.}
|
||||
|
||||
@examples[
|
||||
(define cnp (make-thread-cell '(nerve) #f))
|
||||
(define cp (make-thread-cell '(cancer) #t))
|
||||
|
||||
(thread-cell-ref cnp)
|
||||
(thread-cell-ref cp)
|
||||
|
||||
(thread-cell-set! cnp '(nerve nerve))
|
||||
(thread-cell-set! cp '(cancer cancer))
|
||||
|
||||
(thread-cell-ref cnp)
|
||||
(thread-cell-ref cp)
|
||||
|
||||
(define ch (make-channel))
|
||||
(thread (lambda ()
|
||||
(channel-put ch (thread-cell-ref cnp))
|
||||
(channel-put ch (thread-cell-ref cp))
|
||||
(channel-get ch) ; to wait
|
||||
(channel-put ch (thread-cell-ref cp))))
|
||||
|
||||
(channel-get ch)
|
||||
(channel-get ch)
|
||||
|
||||
(thread-cell-set! cp '(cancer cancer cancer))
|
||||
|
||||
(thread-cell-ref cp)
|
||||
(channel-put ch 'ok)
|
||||
(channel-get ch)
|
||||
]
|
||||
|
||||
@defproc*[([(current-preserved-thread-cell-values) any]
|
||||
[(current-preserved-thread-cell-values [thread-cell-vals any/c]) void?])]{
|
||||
|
||||
When called with no arguments, this procedure produces a
|
||||
@scheme[thread-cell-vals] that represents the current values (in the
|
||||
current thread) for all preserved thread cells.
|
||||
|
||||
When called with a @scheme[thread-cell-vals] generated by a previous
|
||||
call to @scheme[current-preserved-thread-cell-values], the values of
|
||||
all preserved thread cells (in the current thread) are set to the
|
||||
values captured in @scheme[thread-cell-vals]; if a preserved thread
|
||||
cell was created after @scheme[thread-cell-vals] was generated, then
|
||||
the thread cell's value for the current thread reverts to its initial
|
||||
value.}
|
||||
|
13
collects/scribblings/reference/thread-local.scrbl
Normal file
13
collects/scribblings/reference/thread-local.scrbl
Normal file
|
@ -0,0 +1,13 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title[#:tag "mz:thread-local-storage" #:style 'toc]{Thread-Local Storage}
|
||||
|
||||
@tech{Thread cells} provides primitive support for thread-local
|
||||
storage. @tech{Parameters} combine thread cells and continuation marks
|
||||
to support thread-specific, continuation-specific binding.
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@include-section["thread-cells.scrbl"]
|
||||
@include-section["parameters.scrbl"]
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
@title[#:tag "mz:threads"]{Threads}
|
||||
|
||||
See @secref["mz:thread-model"] and @secref["mz:parameter-model"] for
|
||||
basic information on the PLT Scheme thread and parameter model.
|
||||
See @secref["mz:thread-model"] for basic information on the PLT Scheme
|
||||
thread model.
|
||||
|
||||
When a thread is created, it is placed into the management of the
|
||||
@tech{current custodian} and added to the current thread group (see
|
||||
|
@ -61,6 +61,34 @@ Like @scheme[thread], except that ``killing'' the thread through
|
|||
@scheme[kill-thread] or @scheme[custodian-shutdown-all] merely
|
||||
suspends the thread instead of terminating it. }
|
||||
|
||||
@defproc[(call-in-nested-thread [thunk (->any)]
|
||||
[cust custodian? (current-custodian)])
|
||||
any]{
|
||||
|
||||
Creates a nested thread managed by @scheme[cust] to execute
|
||||
@scheme[thunk]. (The nested thread's current custodian is inherited
|
||||
from the creating thread, independent of the @scheme[cust] argument.)
|
||||
The current thread blocks until @scheme[thunk] returns, and the result
|
||||
of the @scheme[call-in-nested-thread] call is the result returned by
|
||||
@scheme[thunk].
|
||||
|
||||
The nested thread's exception handler is initialized to a procedure
|
||||
that jumps to the beginning of the thread and transfers the exception
|
||||
to the original thread. The handler thus terminates the nested thread
|
||||
and re-raises the exception in the original thread.
|
||||
|
||||
If the thread created by @scheme[call-in-nested-thread] dies before
|
||||
@scheme[thunk] returns, the @exnraise[exn:fail] in the original
|
||||
thread. If the original thread is killed before @scheme[thunk]
|
||||
returns, a break is queued for the nested thread.
|
||||
|
||||
If a break is queued for the original thread (with
|
||||
@scheme[break-thread]) while the nested thread is running, the break
|
||||
is redirected to the nested thread. If a break is already queued on
|
||||
the original thread when the nested thread is created, the break is
|
||||
moved to the nested thread. If a break remains queued on the nested
|
||||
thread when it completes, the break is moved to the original thread.}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:threadkill"]{Suspending, Resuming, and Killing Threads}
|
||||
|
||||
|
@ -130,3 +158,68 @@ never interferes with the application of procedures in other
|
|||
threads. For example, if a thread is killed while extracting a
|
||||
character from an input port, the character is either completely
|
||||
consumed or not consumed, and other threads can safely use the port.}
|
||||
|
||||
@defproc[(break-thread [thd thread?]) void?]{
|
||||
|
||||
@index['("threads" "breaking")]{Registers} a break with the specified
|
||||
thread. If breaking is disabled in @scheme[thd], the break will be
|
||||
ignored until breaks are re-enabled (see @secref["mz:breakhandler"]).}
|
||||
|
||||
@defproc[(sleep [secs nonnegative-number? 0]) void?]{
|
||||
|
||||
Causes the current thread to sleep until at least @scheme[secs]
|
||||
seconds have passed after it starts sleeping. A zero value for
|
||||
@scheme[secs] simply acts as a hint to allow other threads to
|
||||
execute. The value of @scheme[secs] can be non-integral to request a
|
||||
sleep duration to any precision; the precision of the actual sleep
|
||||
time is unspecified.}
|
||||
|
||||
@defproc[(thread-running? [thd thread?]) any]{
|
||||
|
||||
@index['("threads" "run state")]{Returns} @scheme[#t] if @scheme[thd]
|
||||
has not terminated and is not suspended, @scheme[#f] otherwise.}
|
||||
|
||||
@defproc[(thread-dead? [thd thread?]) any]{
|
||||
|
||||
Returns @scheme[#t] if @scheme[thd] has terminated, @scheme[#f]
|
||||
otherwise.}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:threadsync"]{Synchronizing Thread State}
|
||||
|
||||
@defproc[(thread-wait [thd thread?]) void?]{
|
||||
|
||||
Blocks execution of the current thread until @scheme[thd] has
|
||||
terminated. Note that @scheme[(thread-wait (current-thread))]
|
||||
deadlocks the current thread, but a break can end the deadlock (if
|
||||
breaking is enabled; see @secref["mz:breakhandler"]).}
|
||||
|
||||
@defproc[(thread-dead-evt [thd thread?]) evt?]{
|
||||
|
||||
Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that is
|
||||
ready if and only if @scheme[thd] has terminated. Unlike using
|
||||
@scheme[thd] directly, however, a reference to the event does not
|
||||
prevent @scheme[thd] from being garbage collected (see
|
||||
@secref["mz:gc-model"]).}
|
||||
|
||||
@defproc[(thread-resume-evt [thd thread?]) evt?]{
|
||||
|
||||
Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that
|
||||
becomes ready when @scheme[thd] is running. (If @scheme[thd] has
|
||||
terminated, the event never becomes ready.) If @scheme[thd] runs and
|
||||
is then suspended after a call to @scheme[thread-resume-evt], the
|
||||
result event remains ready; after each suspend of @scheme[thd] a fresh
|
||||
event is generated to be returned by @scheme[thread-resume-evt]. The
|
||||
result of the event is @scheme[thd], but if @scheme[thd] is never
|
||||
resumed, then reference to the event does not prevent @scheme[thd]
|
||||
from being garbage collected (see @secref["mz:gc-model"]).}
|
||||
|
||||
@defproc[(thread-suspend-evt [thd thread?]) evt?]{
|
||||
|
||||
Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that
|
||||
becomes ready when @scheme[thd] is suspended. (If @scheme[thd] has
|
||||
terminated, the event will never unblock.) If @scheme[thd] is
|
||||
suspended and then resumes after a call to
|
||||
@scheme[thread-suspend-evt], the result event remains ready; after
|
||||
each resume of @scheme[thd] created a fresh event to be returned by
|
||||
@scheme[thread-suspend-evt].}
|
||||
|
|
Loading…
Reference in New Issue
Block a user