ffi/unsafe doc repairs

Closes PR 13143
This commit is contained in:
Matthew Flatt 2012-09-27 08:12:28 -06:00
parent afeeb56fe8
commit 3f59309634
2 changed files with 26 additions and 20 deletions

View File

@ -21,7 +21,7 @@ FFI-based calls to COM object methods.}
@section{Describing COM Interfaces} @section{Describing COM Interfaces}
@defform/subs[(define-com-interface (_id _super-id) @defform/subs[(define-com-interface (_id _super-id)
([method-id ctype-expr maybe-alloc-spec])) ([method-id ctype-expr maybe-alloc-spec] ...))
([maybe-alloc-spec code:blank ([maybe-alloc-spec code:blank
(code:line #:release-with-function function-id) (code:line #:release-with-function function-id)
(code:line #:release-with-method method-id) (code:line #:release-with-method method-id)

View File

@ -321,56 +321,62 @@ Registers a finalizer procedure @racket[finalizer-proc] with the given
@racket[obj], which can be any Racket (GC-able) object. The finalizer @racket[obj], which can be any Racket (GC-able) object. The finalizer
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. (The finalizer is invoked in a @racket[obj] is about to be collected.
thread that is in charge of triggering these will executors.)
See also @racket[register-custodian-shutdown]. See also @racket[register-custodian-shutdown].
The finalizer is invoked in a thread that is in charge of triggering
will executors for @racket[register-finalizer]. The given
@racket[finalizer] procedure should generally not rely on the
environment of the triggering thread, such as its output ports or
custodians, except that relying on a default logger is reasonable.
Finalizers are mostly intended to be used with cpointer objects (for Finalizers are mostly intended to be used with cpointer objects (for
freeing unused memory that is not under GC control), but it can be freeing unused memory that is not under GC control), but it can be
used with any Racket object---even ones that have nothing to do with used with any Racket object---even ones that have nothing to do with
foreign code. Note, however, that the finalizer is registered for the foreign code. Note, however, that the finalizer is registered for the
@italic{Racket} object. If you intend to free a pointer object, then @italic{Racket} object that represents the pointer. If you intend to
you must be careful to not register finalizers for two cpointers that free a pointer object, then you must be careful to not register
point to the same address. Also, be careful to not make the finalizer finalizers for two cpointers that point to the same address. Also, be
a closure that holds on to the object. careful to not make the finalizer a closure that holds on to the
object.
For example, suppose that you're dealing with a foreign function that returns a For example, 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[
(define bytes/free (define @#,racketidfont{_sixteen-bytes/free}
(make-ctype _pointer (make-ctype _pointer
#f (code:comment @#,t{a Racket bytes can be used as a pointer}) #f (code:comment @#,t{a Racket bytes can be used as a pointer})
(lambda (x) (lambda (x)
(let ([b (make-byte-string x)]) (let ([b (make-sized-byte-string x 16)])
(register-finalizer x free) (register-finalizer x free)
b)))) b))))
] ]
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 once the byte string is created. Changing which is no longer needed after the byte string is created. Changing
this to register the finalizer for @racket[b] correct this problem, the example to register the finalizer for @racket[b] correct the problem,
but then @racket[free] will be invoked on it instead of on @racket[x]. but then @racket[free] is invoked @racket[b] it instead of on @racket[x].
In an attempt to fix this, we will be careful and print out a message In the process of fixing this problem, we might be careful and log a message
for debugging: for debugging:
@racketblock[ @racketblock[
(define bytes/free (define @#,racketidfont{_sixteen-bytes/free}
(make-ctype _pointer (make-ctype _pointer
#f (code:comment @#,t{a Racket bytes can be used as a pointer}) #f (code:comment @#,t{a Racket bytes can be used as a pointer})
(lambda (x) (lambda (x)
(let ([b (make-byte-string x)]) (let ([b (make-sized-byte-string x 16)])
(register-finalizer b (register-finalizer b
(lambda (ignored) (lambda (ignored)
(printf "Releasing ~s\n" b) (log-debug (format "Releasing ~s\n" b))
(free x))) (free x)))
b)))) b))))
] ]
but we never see any printout. The problem is that the finalizer is a Now, we never see any logged event. The problem is that the finalizer is a
closure that keeps a reference to @racket[b]. To fix this, you should closure that keeps a reference to @racket[b]. Instead of referencing the
use the input argument to the finalizer. Simply changing value that is finalized, use the input argument to the finalizer; simply changing
@racket[ignored] to @racket[b] will solve this problem. (Removing the @racket[ignored] to @racket[b] above solves the problem. (Removing the
debugging message also avoids the problem, since the finalization debugging message also avoids the problem, since the finalization
procedure would then not close over @racket[b].)} procedure would then not close over @racket[b].)}