parent
8fb8d3c936
commit
f58b99aa74
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
(define collection 'multi)
|
(define collection 'multi)
|
||||||
|
|
||||||
(define version "7.0.0.3")
|
(define version "7.0.0.4")
|
||||||
|
|
||||||
(define deps `("racket-lib"
|
(define deps `("racket-lib"
|
||||||
["racket" #:version ,version]))
|
["racket" #:version ,version]))
|
||||||
|
|
|
@ -11,17 +11,40 @@ deallocated.}
|
||||||
|
|
||||||
@defproc[((allocator [dealloc (any/c . -> . any)]) [alloc procedure?]) procedure?]{
|
@defproc[((allocator [dealloc (any/c . -> . any)]) [alloc procedure?]) procedure?]{
|
||||||
|
|
||||||
Produces a procedure that behaves like @racket[alloc], but the result
|
Produces an @deftech{allocator} procedure that behaves like
|
||||||
of @racket[alloc] is given a finalizer that calls @racket[dealloc] on
|
@racket[alloc], but each result @racket[_v] of the @tech{allocator},
|
||||||
a non-@racket[#f] result if it is not otherwise freed through a deallocator (as
|
if not @racket[#f], is given a finalizer that calls @racket[dealloc]
|
||||||
designated with @racket[deallocator]). In addition, @racket[alloc] is
|
on @racket[_v] --- unless the call has been canceled by applying a
|
||||||
called in @tech{atomic mode} (see @racket[call-as-atomic]); its result is
|
@tech{deallocator} (produced by @racket[deallocator]) to @racket[_v].
|
||||||
received and registered in atomic mode, so that the result is reliably
|
Any existing @racket[dealloc] registered for @racket[_v] is canceled.
|
||||||
freed as long as no exception is raised.
|
|
||||||
|
|
||||||
The @racket[dealloc] procedure itself need not be specifically
|
The resulting @tech{allocator} calls @racket[alloc] in @tech{atomic
|
||||||
designated a deallocator (via @racket[deallocator]). If a deallocator
|
mode} (see @racket[call-as-atomic]). The result from @racket[alloc] is
|
||||||
is called explicitly, it need not be the same as @racket[dealloc].}
|
received and registered in atomic mode, so that the result is reliably
|
||||||
|
deallocated as long as no exception is raised.
|
||||||
|
|
||||||
|
The @racket[dealloc] procedure will be called in atomic mode, and it
|
||||||
|
must obey the same constraints as a finalizer procedure provided to
|
||||||
|
@racket[register-finalizer]. The @racket[dealloc] procedure itself
|
||||||
|
need not be specifically a @tech{deallocator} produced by
|
||||||
|
@racket[deallocator]. If a @tech{deallocator} is called explicitly, it
|
||||||
|
need not be the same as @racket[dealloc].
|
||||||
|
|
||||||
|
When a non-main @tech[#:doc reference.scrbl]{place} exits, after all
|
||||||
|
@tech[#:doc reference.scrbl]{custodian}-shutdown actions, for every
|
||||||
|
@racket[dealloc] still registered via an @tech{allocator} or
|
||||||
|
@tech{retainer} (from @racket[allocator] or @racket[retainer]), the
|
||||||
|
value to deallocate is treated as immediately unreachable. At that
|
||||||
|
point, @racket[dealloc] functions are called in reverse order of their
|
||||||
|
registrations. Note that references in a @racket[dealloc] function's
|
||||||
|
closure do @emph{not} prevent running a @racket[dealloc] function for
|
||||||
|
any other value. If deallocation needs to proceed in an order
|
||||||
|
different than reverse of allocation, use a @tech{retainer} to insert
|
||||||
|
a new deallocation action that will run earlier.
|
||||||
|
|
||||||
|
@history[#:changed "7.0.0.4" @elem{Added atomic mode for @racket[dealloc]
|
||||||
|
and changed non-main place exits to call
|
||||||
|
all remaining @racket[dealloc]s.}]}
|
||||||
|
|
||||||
@deftogether[(
|
@deftogether[(
|
||||||
@defproc[((deallocator [get-arg (list? . -> . any/c) car]) [dealloc procedure?])
|
@defproc[((deallocator [get-arg (list? . -> . any/c) car]) [dealloc procedure?])
|
||||||
|
@ -30,13 +53,11 @@ is called explicitly, it need not be the same as @racket[dealloc].}
|
||||||
procedure?]
|
procedure?]
|
||||||
)]{
|
)]{
|
||||||
|
|
||||||
Produces a procedure that behaves like @racket[dealloc]. The
|
Produces a @deftech{deallocator} procedure that behaves like
|
||||||
@racket[dealloc] procedure is called in @tech{atomic mode} (see
|
@racket[dealloc]. The @tech{deallocator} calls @racket[dealloc] in
|
||||||
@racket[call-as-atomic]), and the reference count on one of its
|
@tech{atomic mode} (see @racket[call-as-atomic]), and for one of its
|
||||||
arguments is decremented; if the reference count reaches zero, no
|
arguments, the it cancels the most recent remaining deallocator
|
||||||
finalizer associated by an @racket[allocator]- or
|
registered by a @tech{allocator} or @tech{retainer}.
|
||||||
@racket[retainer]-wrapped procedure is invoked when the value
|
|
||||||
becomes inaccessible.
|
|
||||||
|
|
||||||
The optional @racket[get-arg] procedure determines which of
|
The optional @racket[get-arg] procedure determines which of
|
||||||
@racket[dealloc]'s arguments correspond to the released object;
|
@racket[dealloc]'s arguments correspond to the released object;
|
||||||
|
@ -52,19 +73,28 @@ The @racket[releaser] procedure is a synonym for
|
||||||
[retain procedure?])
|
[retain procedure?])
|
||||||
procedure?]{
|
procedure?]{
|
||||||
|
|
||||||
Produces a procedure that behaves like @racket[retain]. The procedure
|
Produces a @deftech{retainer} procedure that behaves like
|
||||||
is called in @tech{atomic mode} (see @racket[call-as-atomic]), and the
|
@racket[retain]. A @tech{retainer} acts the same as an
|
||||||
reference count on one of its arguments is incremented, with
|
@tech{allocator} produced by @racket[allocator], except that
|
||||||
@racket[release] recorded as the corresponding release procedure to be
|
|
||||||
called by the finalizer on the retained object (unless some
|
|
||||||
deallocator, as wrapped by @racket[deallocator], is explicitly called
|
|
||||||
first).
|
|
||||||
|
|
||||||
The optional @racket[get-arg] procedure determines which of
|
@itemlist[
|
||||||
@racket[retain]'s arguments correspond to the retained object;
|
|
||||||
|
@item{a @tech{retainer} does not cancel any existing @racket[release]
|
||||||
|
or @racket[_dealloc] registrations when registering
|
||||||
|
@racket[release]; and}
|
||||||
|
|
||||||
|
@item{@racket[release] is registered for a value @racket[_v] that is
|
||||||
|
is an argument to the @tech{retainer}, instead of the result
|
||||||
|
for an @tech{allocator}.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
The optional @racket[get-arg] procedure determines which of the
|
||||||
|
@tech{retainer}'s arguments (that is, which of @racket[retain]'s
|
||||||
|
arguments) correspond to the retained object @racket[_v];
|
||||||
@racket[get-arg] receives a list of arguments passed to
|
@racket[get-arg] receives a list of arguments passed to
|
||||||
@racket[retain], so the default @racket[car] selects the first one.
|
@racket[retain], so the default @racket[car] selects the first one.
|
||||||
|
|
||||||
The @racket[release] procedure itself need not be specifically
|
@history[#:changed "7.0.0.4" @elem{Added atomic mode for @racket[release]
|
||||||
designated a deallocator (via @racket[deallocator]). If a deallocator
|
and changed non-main place exits to call
|
||||||
is called explicitly, it need not be the same as @racket[release].}
|
all remaining @racket[release]s.}]}
|
||||||
|
|
|
@ -303,7 +303,6 @@ Registers a finalizer procedure @racket[finalizer-proc] with the given
|
||||||
is registered with a will executor; see
|
is registered with a will executor; see
|
||||||
@racket[make-will-executor]. The finalizer is invoked when
|
@racket[make-will-executor]. The finalizer is invoked when
|
||||||
@racket[obj] is about to be collected.
|
@racket[obj] is about to be collected.
|
||||||
See also @racket[register-custodian-shutdown].
|
|
||||||
|
|
||||||
The finalizer is invoked in a thread that is in charge of triggering
|
The finalizer is invoked in a thread that is in charge of triggering
|
||||||
will executors for @racket[register-finalizer]. The given
|
will executors for @racket[register-finalizer]. The given
|
||||||
|
@ -320,9 +319,13 @@ foreign code. Note, however, that the finalizer is registered for the
|
||||||
free a pointer object, then you must be careful to not register
|
free a pointer object, then you must be careful to not register
|
||||||
finalizers for two cpointers that point to the same address. Also, be
|
finalizers for two cpointers that point to the same address. Also, be
|
||||||
careful to not make the finalizer a closure that holds on to the
|
careful to not make the finalizer a closure that holds on to the
|
||||||
object.
|
object. Finally, beware that the finalizer is not guaranteed to
|
||||||
|
be run when a place exits; see @racketmodname[ffi/unsafe/alloc]
|
||||||
|
and @racket[register-finalizer-and-custodian-shutdown] for more
|
||||||
|
complete solutions.
|
||||||
|
|
||||||
For example, suppose that you're dealing with a foreign function that returns a
|
As an example for @racket[register-finalizer],
|
||||||
|
suppose that you're dealing with a foreign function that returns a
|
||||||
C string that you should free. Here is an attempt at creating a suitable type:
|
C string that you should free. Here is an attempt at creating a suitable type:
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
|
@ -337,7 +340,7 @@ C string that you should free. Here is an attempt at creating a suitable type:
|
||||||
|
|
||||||
The above code is wrong: the finalizer is registered for @racket[x],
|
The above code is wrong: the finalizer is registered for @racket[x],
|
||||||
which is no longer needed after the byte string is created. Changing
|
which is no longer needed after the byte string is created. Changing
|
||||||
the example to register the finalizer for @racket[b] correct the problem,
|
the example to register the finalizer for @racket[b] corrects the problem,
|
||||||
but then @racket[free] is invoked @racket[b] it instead of on @racket[x].
|
but then @racket[free] is invoked @racket[b] it instead of on @racket[x].
|
||||||
In the process of fixing this problem, we might be careful and log a message
|
In the process of fixing this problem, we might be careful and log a message
|
||||||
for debugging:
|
for debugging:
|
||||||
|
|
70
pkgs/racket-test/tests/racket/ffi-alloc.rkt
Normal file
70
pkgs/racket-test/tests/racket/ffi-alloc.rkt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require racket/place
|
||||||
|
ffi/unsafe
|
||||||
|
ffi/unsafe/alloc)
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(define-syntax-rule (test expect got)
|
||||||
|
(let ([e expect]
|
||||||
|
[g got])
|
||||||
|
(unless (equal? e g)
|
||||||
|
(error 'test "failed: ~s => ~v != ~s => ~v" 'expect e 'got g))))
|
||||||
|
|
||||||
|
(define (check-allocator
|
||||||
|
#:retain? [retain? #f]
|
||||||
|
#:release? [release? #f]
|
||||||
|
#:deallocate? [deallocate? #f])
|
||||||
|
(printf "~s\n" (list retain? release? deallocate?))
|
||||||
|
(define done? #f)
|
||||||
|
(define released? #f)
|
||||||
|
(let ([x (((allocator (lambda (v) (set! done? (symbol? v))))
|
||||||
|
gensym))])
|
||||||
|
(collect-garbage)
|
||||||
|
(sync (system-idle-evt))
|
||||||
|
(test #f done?)
|
||||||
|
(when retain?
|
||||||
|
(((retainer (lambda (v) (set! released? (symbol? v)))) void) x))
|
||||||
|
(when release?
|
||||||
|
(((releaser) void) x))
|
||||||
|
(when deallocate?
|
||||||
|
(((deallocator) void) x))
|
||||||
|
(void/reference-sink x)
|
||||||
|
(collect-garbage)
|
||||||
|
(sync (system-idle-evt))
|
||||||
|
(when retain?
|
||||||
|
(collect-garbage)
|
||||||
|
(sync (system-idle-evt)))
|
||||||
|
(test (or (not deallocate?) (and retain? (not release?))) done?)
|
||||||
|
(test (and retain? (not (or deallocate? release?))) released?)))
|
||||||
|
|
||||||
|
(unless (eq? 'cgc (system-type 'gc))
|
||||||
|
(check-allocator)
|
||||||
|
(check-allocator #:deallocate? #t)
|
||||||
|
(check-allocator #:retain? #t #:deallocate? #t)
|
||||||
|
(check-allocator #:retain? #t #:deallocate? #t #:release? #t)
|
||||||
|
(check-allocator #:retain? #t #:deallocate? #f #:release? #t))
|
||||||
|
|
||||||
|
(when (place-enabled?)
|
||||||
|
;; Make sure deallocators are run when a place exits,
|
||||||
|
;; and make sure they're run in the right order:
|
||||||
|
(define p (go-in-place))
|
||||||
|
(define bstr (make-shared-bytes 2 0))
|
||||||
|
(place-channel-put p bstr)
|
||||||
|
(void (place-wait p))
|
||||||
|
(test #"\x0A\x64" bstr)))
|
||||||
|
|
||||||
|
(define (go-in-place)
|
||||||
|
(place p
|
||||||
|
(define bstr (place-channel-get p))
|
||||||
|
;; These 10 should be deallocated later
|
||||||
|
(define orig
|
||||||
|
(for/list ([i 10])
|
||||||
|
(((allocator (lambda (v) (bytes-set! bstr 1 (+ (bytes-ref bstr 1) (bytes-ref bstr 0)))))
|
||||||
|
gensym))))
|
||||||
|
;; These 10 should be deallocated earlier:
|
||||||
|
(define next
|
||||||
|
(for/list ([i 10])
|
||||||
|
(((allocator (lambda (v) (bytes-set! bstr 0 (+ (bytes-ref bstr 0) 1))))
|
||||||
|
gensym))))
|
||||||
|
(list next orig)))
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require ffi/unsafe
|
(require ffi/unsafe
|
||||||
|
(only-in '#%unsafe
|
||||||
|
unsafe-add-post-custodian-shutdown
|
||||||
|
unsafe-start-atomic
|
||||||
|
unsafe-end-atomic)
|
||||||
"atomic.rkt")
|
"atomic.rkt")
|
||||||
|
|
||||||
(provide allocator deallocator retainer
|
(provide allocator deallocator retainer
|
||||||
|
@ -7,6 +11,12 @@
|
||||||
|
|
||||||
(define allocated (make-late-weak-hasheq))
|
(define allocated (make-late-weak-hasheq))
|
||||||
|
|
||||||
|
;; A `node` is used to implement a doubly linked list that
|
||||||
|
;; records the allocation order. That way, deallocators can
|
||||||
|
;; be called in reverse order when a non-main place exits.
|
||||||
|
(struct node (weak-val proc [next #:mutable] [prev #:mutable] rest)
|
||||||
|
#:authentic)
|
||||||
|
|
||||||
;; A way to show all still-unfinalized values on exit:
|
;; A way to show all still-unfinalized values on exit:
|
||||||
#;
|
#;
|
||||||
(plumber-add-flush! (current-plumber)
|
(plumber-add-flush! (current-plumber)
|
||||||
|
@ -15,13 +25,35 @@
|
||||||
(printf "~s\n" k))))
|
(printf "~s\n" k))))
|
||||||
|
|
||||||
(define (deallocate v)
|
(define (deallocate v)
|
||||||
;; Called as a finalizer, we we assume that the
|
;; Called either as finalizer (in the finalizer thread) or
|
||||||
;; enclosing thread will not be interrupted.
|
;; as a place is about to exit. Run in atomic mode to
|
||||||
|
;; avoid a race with a place exit.
|
||||||
|
(unsafe-start-atomic)
|
||||||
(let ([ds (hash-ref allocated v #f)])
|
(let ([ds (hash-ref allocated v #f)])
|
||||||
(when ds
|
(when ds
|
||||||
(hash-remove! allocated v)
|
(hash-remove! allocated v)
|
||||||
(for ([d (in-list ds)])
|
(let loop ([ds ds])
|
||||||
(d v)))))
|
(when ds
|
||||||
|
(remove-node! ds)
|
||||||
|
((node-proc ds) v)
|
||||||
|
(loop (node-rest ds))))))
|
||||||
|
(unsafe-end-atomic))
|
||||||
|
|
||||||
|
(define (deallocate-one v expected-ds)
|
||||||
|
;; Called for a place exit.
|
||||||
|
(let ([ds (hash-ref allocated v #f)])
|
||||||
|
(cond
|
||||||
|
[(eq? ds expected-ds)
|
||||||
|
(define rest-ds (node-rest ds))
|
||||||
|
(if rest-ds
|
||||||
|
(hash-set! allocated v rest-ds)
|
||||||
|
(hash-remove! allocated v))
|
||||||
|
(remove-node! ds)
|
||||||
|
((node-proc ds) v)]
|
||||||
|
[else
|
||||||
|
;; Not the expected node. Maybe an allocator
|
||||||
|
;; replaced existing allocations/retains.
|
||||||
|
(remove-node! expected-ds)])))
|
||||||
|
|
||||||
(define ((allocator d) proc)
|
(define ((allocator d) proc)
|
||||||
(rename
|
(rename
|
||||||
|
@ -30,7 +62,9 @@
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let ([v (apply proc args)])
|
(let ([v (apply proc args)])
|
||||||
(when v
|
(when v
|
||||||
(hash-set! allocated v (list d))
|
(define ds (node (make-late-weak-box v) d #f #f #f))
|
||||||
|
(add-node! ds)
|
||||||
|
(hash-set! allocated v ds)
|
||||||
(register-finalizer v deallocate))
|
(register-finalizer v deallocate))
|
||||||
v))))
|
v))))
|
||||||
proc))
|
proc))
|
||||||
|
@ -44,9 +78,11 @@
|
||||||
(let ([v (get-arg args)])
|
(let ([v (get-arg args)])
|
||||||
(let ([ds (hash-ref allocated v #f)])
|
(let ([ds (hash-ref allocated v #f)])
|
||||||
(when ds
|
(when ds
|
||||||
(if (null? (cdr ds))
|
(remove-node! ds)
|
||||||
(hash-remove! allocated v)
|
(define rest-ds (node-rest ds))
|
||||||
(hash-set! allocated v (cdr ds)))))))))
|
(if rest-ds
|
||||||
|
(hash-set! allocated v rest-ds)
|
||||||
|
(hash-remove! allocated v))))))))
|
||||||
proc))
|
proc))
|
||||||
|
|
||||||
(define ((retainer d [get-arg car]) proc)
|
(define ((retainer d [get-arg car]) proc)
|
||||||
|
@ -57,8 +93,12 @@
|
||||||
(begin0
|
(begin0
|
||||||
(apply proc args)
|
(apply proc args)
|
||||||
(let ([v (get-arg args)])
|
(let ([v (get-arg args)])
|
||||||
(let ([ds (hash-ref allocated v null)])
|
(define next-ds (hash-ref allocated v #f))
|
||||||
(hash-set! allocated v (cons d ds))))))))
|
(define ds (node (make-late-weak-box v) d #f #f next-ds))
|
||||||
|
(add-node! ds)
|
||||||
|
(hash-set! allocated v ds)
|
||||||
|
(unless next-ds
|
||||||
|
(register-finalizer v deallocate)))))))
|
||||||
proc))
|
proc))
|
||||||
|
|
||||||
(define (rename new orig)
|
(define (rename new orig)
|
||||||
|
@ -70,3 +110,36 @@
|
||||||
(if n
|
(if n
|
||||||
(procedure-rename new n)
|
(procedure-rename new n)
|
||||||
new))))
|
new))))
|
||||||
|
|
||||||
|
;; ----------------------------------------
|
||||||
|
|
||||||
|
(define all-nodes #f)
|
||||||
|
|
||||||
|
(define (add-node! ds)
|
||||||
|
(set-node-next! ds all-nodes)
|
||||||
|
(when all-nodes
|
||||||
|
(set-node-prev! all-nodes ds))
|
||||||
|
(set! all-nodes ds))
|
||||||
|
|
||||||
|
(define (remove-node! ds)
|
||||||
|
(define prev (node-prev ds))
|
||||||
|
(define next (node-next ds))
|
||||||
|
(if prev
|
||||||
|
(set-node-next! prev next)
|
||||||
|
(set! all-nodes next))
|
||||||
|
(when next
|
||||||
|
(set-node-prev! next prev)))
|
||||||
|
|
||||||
|
(define (release-all)
|
||||||
|
(define ds all-nodes)
|
||||||
|
(when ds
|
||||||
|
(define v (weak-box-value (node-weak-val ds)))
|
||||||
|
(cond
|
||||||
|
[v (deallocate-one v ds)]
|
||||||
|
[else
|
||||||
|
(log-error "ffi/unsafe/alloc: internal error with a value deallocated by ~s" (node-proc ds))
|
||||||
|
(remove-node! ds)])
|
||||||
|
(release-all)))
|
||||||
|
|
||||||
|
;; This is a no-op in the main place:
|
||||||
|
(unsafe-add-post-custodian-shutdown release-all)
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
unsafe-make-custodian-at-root
|
unsafe-make-custodian-at-root
|
||||||
unsafe-custodian-register
|
unsafe-custodian-register
|
||||||
unsafe-custodian-unregister
|
unsafe-custodian-unregister
|
||||||
|
unsafe-add-post-custodian-shutdown
|
||||||
unsafe-register-process-global
|
unsafe-register-process-global
|
||||||
unsafe-get-place-table
|
unsafe-get-place-table
|
||||||
unsafe-make-security-guard-at-root
|
unsafe-make-security-guard-at-root
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
[check-not-unsafe-undefined/assign (known-procedure 4)]
|
[check-not-unsafe-undefined/assign (known-procedure 4)]
|
||||||
[prop:chaperone-unsafe-undefined (known-constant)]
|
[prop:chaperone-unsafe-undefined (known-constant)]
|
||||||
[unsafe-abort-current-continuation/no-wind (known-procedure 4)]
|
[unsafe-abort-current-continuation/no-wind (known-procedure 4)]
|
||||||
|
[unsafe-add-post-custodian-shutdown (known-procedure 2)]
|
||||||
[unsafe-box*-cas! (known-procedure 8)]
|
[unsafe-box*-cas! (known-procedure 8)]
|
||||||
[unsafe-bytes-length (known-procedure/succeeds 2)]
|
[unsafe-bytes-length (known-procedure/succeeds 2)]
|
||||||
[unsafe-bytes-ref (known-procedure 4)]
|
[unsafe-bytes-ref (known-procedure 4)]
|
||||||
|
|
|
@ -558,6 +558,7 @@
|
||||||
place-channel place-dead-evt place-kill place-message-allowed?
|
place-channel place-dead-evt place-kill place-message-allowed?
|
||||||
dynamic-place place-wait place-pumper-threads place-shared?
|
dynamic-place place-wait place-pumper-threads place-shared?
|
||||||
unsafe-get-place-table
|
unsafe-get-place-table
|
||||||
|
unsafe-add-post-custodian-shutdown
|
||||||
|
|
||||||
_bool _bytes _short_bytes _double _double* _fixint _fixnum _float _fpointer _gcpointer
|
_bool _bytes _short_bytes _double _double* _fixint _fixnum _float _fpointer _gcpointer
|
||||||
_int16 _int32 _int64 _int8 _longdouble _pointer _scheme _stdbool _void
|
_int16 _int32 _int64 _int8 _longdouble _pointer _scheme _stdbool _void
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
[(_ id ...)
|
[(_ id ...)
|
||||||
(begin (define-place-not-yet-available id) ...)]))
|
(begin (define-place-not-yet-available id) ...)]))
|
||||||
|
|
||||||
|
;; This operation adds shutdown thunks to a non-main place, so it's a
|
||||||
|
;; no-op for now:
|
||||||
|
(define (unsafe-add-post-custodian-shutdown proc)
|
||||||
|
(void))
|
||||||
|
|
||||||
(define-place-not-yet-available
|
(define-place-not-yet-available
|
||||||
place-break
|
place-break
|
||||||
place-channel-get
|
place-channel-get
|
||||||
|
|
|
@ -250,6 +250,7 @@ typedef struct Thread_Local_Variables {
|
||||||
intptr_t scheme_current_cont_mark_pos_;
|
intptr_t scheme_current_cont_mark_pos_;
|
||||||
struct Scheme_Custodian *main_custodian_;
|
struct Scheme_Custodian *main_custodian_;
|
||||||
struct Scheme_Hash_Table *limited_custodians_;
|
struct Scheme_Hash_Table *limited_custodians_;
|
||||||
|
struct Scheme_Object *post_custodian_shutdowns_;
|
||||||
struct Scheme_Plumber *initial_plumber_;
|
struct Scheme_Plumber *initial_plumber_;
|
||||||
struct Scheme_Config *initial_config_;
|
struct Scheme_Config *initial_config_;
|
||||||
struct Scheme_Thread *swap_target_;
|
struct Scheme_Thread *swap_target_;
|
||||||
|
@ -628,6 +629,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
|
||||||
#define main_custodian XOA (scheme_get_thread_local_variables()->main_custodian_)
|
#define main_custodian XOA (scheme_get_thread_local_variables()->main_custodian_)
|
||||||
#define last_custodian XOA (scheme_get_thread_local_variables()->last_custodian_)
|
#define last_custodian XOA (scheme_get_thread_local_variables()->last_custodian_)
|
||||||
#define limited_custodians XOA (scheme_get_thread_local_variables()->limited_custodians_)
|
#define limited_custodians XOA (scheme_get_thread_local_variables()->limited_custodians_)
|
||||||
|
#define post_custodian_shutdowns XOA (scheme_get_thread_local_variables()->post_custodian_shutdowns_)
|
||||||
#define initial_plumber XOA (scheme_get_thread_local_variables()->initial_plumber_)
|
#define initial_plumber XOA (scheme_get_thread_local_variables()->initial_plumber_)
|
||||||
#define initial_config XOA (scheme_get_thread_local_variables()->initial_config_)
|
#define initial_config XOA (scheme_get_thread_local_variables()->initial_config_)
|
||||||
#define swap_target XOA (scheme_get_thread_local_variables()->swap_target_)
|
#define swap_target XOA (scheme_get_thread_local_variables()->swap_target_)
|
||||||
|
|
|
@ -590,6 +590,8 @@ void scheme_place_instance_destroy(int force)
|
||||||
else
|
else
|
||||||
scheme_run_atexit_closers_on_all(force_more_closed_after);
|
scheme_run_atexit_closers_on_all(force_more_closed_after);
|
||||||
|
|
||||||
|
scheme_run_post_custodian_shutdown();
|
||||||
|
|
||||||
scheme_release_fd_semaphores();
|
scheme_release_fd_semaphores();
|
||||||
|
|
||||||
scheme_release_file_descriptor();
|
scheme_release_file_descriptor();
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#define USE_COMPILED_STARTUP 1
|
#define USE_COMPILED_STARTUP 1
|
||||||
|
|
||||||
#define EXPECTED_PRIM_COUNT 1431
|
#define EXPECTED_PRIM_COUNT 1432
|
||||||
|
|
||||||
#ifdef MZSCHEME_SOMETHING_OMITTED
|
#ifdef MZSCHEME_SOMETHING_OMITTED
|
||||||
# undef USE_COMPILED_STARTUP
|
# undef USE_COMPILED_STARTUP
|
||||||
|
|
|
@ -873,6 +873,7 @@ Scheme_Thread *scheme_do_close_managed(Scheme_Custodian *m, Scheme_Exit_Closer_F
|
||||||
Scheme_Custodian *scheme_get_current_custodian(void);
|
Scheme_Custodian *scheme_get_current_custodian(void);
|
||||||
void scheme_run_atexit_closers_on_all(Scheme_Exit_Closer_Func alt);
|
void scheme_run_atexit_closers_on_all(Scheme_Exit_Closer_Func alt);
|
||||||
void scheme_run_atexit_closers(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data);
|
void scheme_run_atexit_closers(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data);
|
||||||
|
void scheme_run_post_custodian_shutdown();
|
||||||
|
|
||||||
typedef struct Scheme_Security_Guard {
|
typedef struct Scheme_Security_Guard {
|
||||||
Scheme_Object so;
|
Scheme_Object so;
|
||||||
|
|
|
@ -13,12 +13,12 @@
|
||||||
consistently.)
|
consistently.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MZSCHEME_VERSION "7.0.0.3"
|
#define MZSCHEME_VERSION "7.0.0.4"
|
||||||
|
|
||||||
#define MZSCHEME_VERSION_X 7
|
#define MZSCHEME_VERSION_X 7
|
||||||
#define MZSCHEME_VERSION_Y 0
|
#define MZSCHEME_VERSION_Y 0
|
||||||
#define MZSCHEME_VERSION_Z 0
|
#define MZSCHEME_VERSION_Z 0
|
||||||
#define MZSCHEME_VERSION_W 3
|
#define MZSCHEME_VERSION_W 4
|
||||||
|
|
||||||
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
|
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
|
||||||
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)
|
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)
|
||||||
|
|
|
@ -335,6 +335,8 @@ static Scheme_Object *unsafe_make_custodian_at_root(int argc, Scheme_Object *arg
|
||||||
static Scheme_Object *unsafe_custodian_register(int argc, Scheme_Object *argv[]);
|
static Scheme_Object *unsafe_custodian_register(int argc, Scheme_Object *argv[]);
|
||||||
static Scheme_Object *unsafe_custodian_unregister(int argc, Scheme_Object *argv[]);
|
static Scheme_Object *unsafe_custodian_unregister(int argc, Scheme_Object *argv[]);
|
||||||
|
|
||||||
|
static Scheme_Object *unsafe_add_post_custodian_shutdown(int argc, Scheme_Object *argv[]);
|
||||||
|
|
||||||
static Scheme_Object *unsafe_register_process_global(int argc, Scheme_Object *argv[]);
|
static Scheme_Object *unsafe_register_process_global(int argc, Scheme_Object *argv[]);
|
||||||
static Scheme_Object *unsafe_get_place_table(int argc, Scheme_Object *argv[]);
|
static Scheme_Object *unsafe_get_place_table(int argc, Scheme_Object *argv[]);
|
||||||
static Scheme_Object *unsafe_set_on_atomic_timeout(int argc, Scheme_Object *argv[]);
|
static Scheme_Object *unsafe_set_on_atomic_timeout(int argc, Scheme_Object *argv[]);
|
||||||
|
@ -478,6 +480,12 @@ extern BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved);
|
||||||
|
|
||||||
SHARED_OK Scheme_Object *initial_cmdline_vec;
|
SHARED_OK Scheme_Object *initial_cmdline_vec;
|
||||||
|
|
||||||
|
#if defined(MZ_USE_PLACES)
|
||||||
|
# define RUNNING_IN_ORIGINAL_PLACE (scheme_current_place_id == 0)
|
||||||
|
#else
|
||||||
|
# define RUNNING_IN_ORIGINAL_PLACE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
/* initialization */
|
/* initialization */
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
@ -646,6 +654,8 @@ scheme_init_unsafe_thread (Scheme_Startup_Env *env)
|
||||||
ADD_PRIM_W_ARITY("unsafe-custodian-register", unsafe_custodian_register, 5, 5, env);
|
ADD_PRIM_W_ARITY("unsafe-custodian-register", unsafe_custodian_register, 5, 5, env);
|
||||||
ADD_PRIM_W_ARITY("unsafe-custodian-unregister", unsafe_custodian_unregister, 2, 2, env);
|
ADD_PRIM_W_ARITY("unsafe-custodian-unregister", unsafe_custodian_unregister, 2, 2, env);
|
||||||
|
|
||||||
|
ADD_PRIM_W_ARITY("unsafe-add-post-custodian-shutdown", unsafe_add_post_custodian_shutdown, 1, 1, env);
|
||||||
|
|
||||||
ADD_PRIM_W_ARITY("unsafe-register-process-global", unsafe_register_process_global, 2, 2, env);
|
ADD_PRIM_W_ARITY("unsafe-register-process-global", unsafe_register_process_global, 2, 2, env);
|
||||||
ADD_PRIM_W_ARITY("unsafe-get-place-table", unsafe_get_place_table, 0, 0, env);
|
ADD_PRIM_W_ARITY("unsafe-get-place-table", unsafe_get_place_table, 0, 0, env);
|
||||||
|
|
||||||
|
@ -1916,6 +1926,40 @@ void do_run_atexit_closers_on_all()
|
||||||
scheme_run_atexit_closers_on_all(NULL);
|
scheme_run_atexit_closers_on_all(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Scheme_Object *unsafe_add_post_custodian_shutdown(int argc, Scheme_Object *argv[])
|
||||||
|
{
|
||||||
|
scheme_check_proc_arity("unsafe-add-post-custodian-shutdown", 0, 0, argc, argv);
|
||||||
|
|
||||||
|
#if defined(MZ_USE_PLACES)
|
||||||
|
if (!RUNNING_IN_ORIGINAL_PLACE) {
|
||||||
|
if (!post_custodian_shutdowns) {
|
||||||
|
REGISTER_SO(post_custodian_shutdowns);
|
||||||
|
post_custodian_shutdowns = scheme_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
post_custodian_shutdowns = scheme_make_pair(argv[0], post_custodian_shutdowns);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return scheme_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scheme_run_post_custodian_shutdown()
|
||||||
|
{
|
||||||
|
#if defined(MZ_USE_PLACES)
|
||||||
|
if (post_custodian_shutdowns) {
|
||||||
|
Scheme_Object *proc;
|
||||||
|
scheme_start_in_scheduler();
|
||||||
|
while (SCHEME_PAIRP(post_custodian_shutdowns)) {
|
||||||
|
proc = SCHEME_CAR(post_custodian_shutdowns);
|
||||||
|
post_custodian_shutdowns = SCHEME_CDR(post_custodian_shutdowns);
|
||||||
|
_scheme_apply_multi(proc, 0, NULL);
|
||||||
|
}
|
||||||
|
scheme_end_in_scheduler();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void scheme_set_atexit(Scheme_At_Exit_Proc p)
|
void scheme_set_atexit(Scheme_At_Exit_Proc p)
|
||||||
{
|
{
|
||||||
replacement_at_exit = p;
|
replacement_at_exit = p;
|
||||||
|
@ -1923,12 +1967,6 @@ void scheme_set_atexit(Scheme_At_Exit_Proc p)
|
||||||
|
|
||||||
void scheme_add_atexit_closer(Scheme_Exit_Closer_Func f)
|
void scheme_add_atexit_closer(Scheme_Exit_Closer_Func f)
|
||||||
{
|
{
|
||||||
#if defined(MZ_USE_PLACES)
|
|
||||||
# define RUNNING_IN_ORIGINAL_PLACE (scheme_current_place_id == 0)
|
|
||||||
#else
|
|
||||||
# define RUNNING_IN_ORIGINAL_PLACE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!cust_closers) {
|
if (!cust_closers) {
|
||||||
if (RUNNING_IN_ORIGINAL_PLACE) {
|
if (RUNNING_IN_ORIGINAL_PLACE) {
|
||||||
scheme_atexit(do_run_atexit_closers_on_all);
|
scheme_atexit(do_run_atexit_closers_on_all);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user