parent
30cebe621a
commit
b587fa15d3
|
@ -415,44 +415,45 @@ complete solutions.
|
||||||
|
|
||||||
As an example for @racket[register-finalizer],
|
As an example for @racket[register-finalizer],
|
||||||
suppose that you're dealing with a foreign function that returns a
|
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 pointer that you should free, but you mostly want to use the memory
|
||||||
|
at a 16-byte offset. Here is an attempt at creating a suitable type:
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
(define @#,racketidfont{_sixteen-bytes/free}
|
(define @#,racketidfont{_pointer-at-sixteen/free}
|
||||||
(make-ctype _pointer
|
(make-ctype _pointer
|
||||||
#f (code:comment @#,t{a Racket bytes can be used as a pointer})
|
#f (code:comment @#,t{i.e., just @racket[_pointer] as an argument type})
|
||||||
(lambda (x)
|
(lambda (x)
|
||||||
(let ([b (make-sized-byte-string x 16)])
|
(let ([p (ptr-add x 16)])
|
||||||
(register-finalizer x free)
|
(register-finalizer x free)
|
||||||
b))))
|
p))))
|
||||||
]
|
]
|
||||||
|
|
||||||
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 new pointer @racket[p] is created. Changing
|
||||||
the example to register the finalizer for @racket[b] corrects the problem,
|
the example to register the finalizer for @racket[p] corrects the problem,
|
||||||
but then @racket[free] is invoked @racket[b] it instead of on @racket[x].
|
but then @racket[free] is invoked @racket[p] 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:
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
(define @#,racketidfont{_sixteen-bytes/free}
|
(define @#,racketidfont{_pointer-at-sixteen/free}
|
||||||
(make-ctype _pointer
|
(make-ctype _pointer
|
||||||
#f (code:comment @#,t{a Racket bytes can be used as a pointer})
|
#f
|
||||||
(lambda (x)
|
(lambda (x)
|
||||||
(let ([b (make-sized-byte-string x 16)])
|
(let ([p (ptr-add x 16)])
|
||||||
(register-finalizer b
|
(register-finalizer p
|
||||||
(lambda (ignored)
|
(lambda (ignored)
|
||||||
(log-debug (format "Releasing ~s\n" b))
|
(log-debug (format "Releasing ~s\n" p))
|
||||||
(free x)))
|
(free x)))
|
||||||
b))))
|
p))))
|
||||||
]
|
]
|
||||||
|
|
||||||
Now, we never see any logged event. 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]. Instead of referencing the
|
closure that keeps a reference to @racket[p]. Instead of referencing the
|
||||||
value that is finalized, 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] above solves the problem. (Removing the
|
@racket[ignored] to @racket[p] 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[p].)}
|
||||||
|
|
||||||
|
|
||||||
@deftogether[(
|
@deftogether[(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user