[racket] FFI callback object pointer

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sat Jul 17 10:08:09 EDT 2010

At Sat, 17 Jul 2010 15:18:44 +0200, Thomas Chust wrote:
> 2010/7/17 gabor papp <gabor.lists at mndl.hu>:
> > [...]
> > What I'm trying to do is passing a boxed variable to the FFI module, and
> > when the C library changes the variable it calls the set callback, in which
> > I set the content of the box.
> >
> > I would like to pass the box through the client-data pointer, so the
> > callback can do this, but I'm not sure how to do it. Is it possible to
> > achieve something like this with FFI?
> > [...]
> Hello Gabor,
> nearly everything is possible ;-)
> I think you should consider encapsulating the type of values that can
> be passed around and the box to store them in the closure of the
> getter and setter callbacks, which may be much more convenient than
> creating a C data structure that can hold this information.

I agree.

The main problem with passing a Racket box as the `client-data' is that
the GC cannot see it. So, you'd have to use an immobile cell created
with `malloc-immobile-cell' and explicitly free it

It's simpler to use a closure and ignore the `client-data' argument at
the C level. That is, the foreign library supports `client-data' to
effectively implement closures, but you already have closures in
Racket. So just pass `#f' for `client-data' and ignore the second
argument in the callback, and use a function that closure over whatever
needs to be set.

A catch with the closure approach is that you have to make sure that
the closure is not GC'ed while it is registered with the foreign
library. If you just have a few callbacks that are `define'd at a
module top level (as in Thomas's code), then it's not problem, since
the callbacks won't be GC'ed. If there's no particular reason that the
callabcks avoid GC, though, see the `#:keep' argument of `_fun' and
`_closure' for some other options.

Posted on the users mailing list.