[ocaml-ctypes] Lifecycle of a callback?
yallop at gmail.com
Tue Oct 21 14:13:21 BST 2014
On 21 October 2014 13:24, Trevor Smith <trevorsummerssmith at gmail.com> wrote:
> In the libuv bindings I am working on there is need for user callbacks. A
> user registers the callback with a function, and then at an arbitrary point
> in time later, the callback code is actually ran (started when the user
> starts the libuv event loop). I had naively thought that I would need to
> keep a reference to the user callback and then release this reference after
> the user callback was actually called (because the callback would be used at
> an arbitrary point in the future and could get gc'd).
Yes, that's exactly right.
> I made an example this morning to test this out, however I cannot get it to
> fail (ie throw an CallToExpiredClosure).
> Perhaps my assumption is wrong, and I do not have to keep around a
> reference? Or my test is not testing what I think it is?
It's the latter. Your callback function
let cb fs = Printf.printf "XXX Called '%s'\n" (getf !@fs C._path) in
doesn't reference anything from the local environment, so no closure
is allocated, and there's nothing for the GC to collect. If you
change the function to reference the local environment -- for example,
by adding a dummy use of 'data'
let cb fs =
let _ = Obj.repr data in
Printf.printf "XXX Called '%s'\n" (getf !@fs C._path) in
then the test fails with CallToExpiredClosure as expected. Besides
inspecting the source of the function, you can check whether a closure
is allocated by attempting to add a finaliser to the function, which
will fail for non-closures, or by inspecting the generated cmm (using
-dcmm), which looks like this for the non-closure case
(i.e. cb is just a reference to a static function), and like this for
the closure case:
(cb/1325 (alloc 3319 "camlTest_lifecycle__cb_1325" 3 data/1324)
I hope that helps,
More information about the Ctypes