[racket] FFI: struct of callbacks vs. GC

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Mon Nov 12 08:58:21 EST 2012

"Converted Racket function" is meant to be the function that you're
passing to the foreign function. That is, there's no distinction
between "the Racket function" and "the converted Racket function". 
I'll work on that phrasing in the docs.

So, can you say more about why you expect the Racket function to be
retained in your example?

At Mon, 12 Nov 2012 08:49:44 -0500, Jon Zeppieri wrote:
> OK, that test worked.
> 
> I guess I don't really understand the #:keep documentation. For the
> default case of #t, it reads "#t — the callback stays in memory as
> long as the converted Racket function is reachable." What is the
> "converted Racket function"? I was ignoring "converted," I think,
> mainly because I'm not sure what distinction is being drawn here, if
> not between the Racket function and the callback.
> 
> I mean that I was counting on the reachability of the Racket function
> guaranteeing the reachability of the callback. Are there three objects
> in play here: the Racket function, the converted Racket function, and
> the callback?
> 
> Thanks for your help.
> 
> -Jon
> 
> On Mon, Nov 12, 2012 at 7:57 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> > Callbacks never move, and they correctly deal with movable values
> > referenced in the closure, so the only issue should be whether the GC
> > reclaims a cllacbk. It can be tricky to make sure that a callback is
> > not GCed too early, though.
> >
> > As a test, you might try specifying `#:keep' as a function that put its
> > callback argument in a new immobile cell. Assuming that you never free
> > the cell, then the callback should never get GCed.
> >
> >
> > At Mon, 12 Nov 2012 01:14:03 -0500, Jon Zeppieri wrote:
> >> I'm running into a problem using the ffi, and I think it has to do
> >> with passing a struct containing a number of callbacks to a foreign
> >> function. The foreign code hangs on to this struct and may invoke the
> >> callbacks any number of times.
> >>
> >> When the GC runs, things go south quickly. I'm pretty sure the reason
> >> is that the callbacks are getting moved by the GC, and the foreign
> >> code is left with a struct full of bad pointers. This seems to be
> >> confirmed by the ffi docs:
> >>
> >> ===
> >> Structs are allocated as atomic blocks, which means that the garbage
> >> collector ignores their content. Thus, struct fields can hold only
> >> non-pointer values, pointers to memory outside the GC’s control, and
> >> otherwise-reachable pointers to immobile GC-managed values (such as
> >> those allocated with malloc and 'internal or 'internal-atomic).
> >> ===
> >>
> >> I found this old message from Matthew
> >> [http://lists.racket-lang.org/users/archive/2010-July/040480.html],
> >> but I think his suggestion to define the callbacks at the module
> >> top-level only prevents them from being reclaimed, not from being
> >> moved.
> >>
> >> It seems that I need either an immobile closure pointer or a way of
> >> sending callbacks to the foreign code without making them invisible to
> >> the GC.
> >>
> >> Any ideas?
> >>
> >> -Jon
> >>
> >> ____________________
> >>   Racket Users list:
> >>   http://lists.racket-lang.org/users


Posted on the users mailing list.