[racket] FFI: struct of callbacks vs. GC

From: Jon Zeppieri (zeppieri at gmail.com)
Date: Mon Nov 12 08:49:44 EST 2012

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.