[racket] FFI: struct of callbacks vs. GC

From: Jon Zeppieri (zeppieri at gmail.com)
Date: Mon Nov 12 10:25:54 EST 2012

Well, in the current version, all of the racket functions corresponding to the callbacks are defined at the module top-level. It's likely that in some previous version, I wasn't holding on to them. 

I'm now thinking that the callback issue might be a red herring. Even with the #:keep change the program still crashes about 50% of the time. I'm sure I have some other bug lurking around here...

On Nov 12, 2012, at 8:58 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:

> "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.