[gambit-list] Incrementing reference to a Scheme object

Marc Feeley feeley at iro.umontreal.ca
Thu Oct 31 09:39:15 EDT 2013


On Oct 31, 2013, at 8:08 AM, Vijay Mathew <vijay.the.lisper at gmail.com> wrote:

> What is the right way to prevent a Scheme object referenced by a C object from being garbage collected?
> 
> For example, I have a structure:
> 
> struct Callback {
>       ___SCMOBJ cbfn;
> };
> 
> where `cbfn' is a procedure defined in Scheme. I want it to be garbage collected only after the Callback object itself is destroyed.

There are a few ways to achieve this.  One approach depends on the allocation kind for the Scheme object contained in cbfn.

If cbfn is permanently allocated (allocation kind = ___PERM), then you don't need to protect it.  Functions with no free variables are allocated this way.

If cbfn is a still object (allocation kind = ___STILL), then you can increment its reference count with ___still_obj_refcount_inc(cbfn) when you store it in the structure, and then call ___still_obj_refcount_dec(cbfn) when the structure is destroyed.

If cbfn is a movable object (allocation kind = ___MOVABLE0/1/2), then you can't store the object in the structure because its address will change when there is a GC, and the GC isn't aware that a reference to the object is in a C structure, so it can't update it.  Unfortunately, functions with free variables are allocated as movable objects.

A better approach, that does not depend on the allocation kind, is to wrap the object in a reference counted structure allocated with ___alloc_rc.  The function ___alloc_rc can be used to allocate blocks of memory in the C heap, with the same API as "malloc", except that ___release_rc must be called to release the block instead of calling "free".  There are two advantages to a reference counted structure, 1) they have a reference count managed with ___addref_rc and ___release_rc, and 2) a GC managed Scheme object can be attached to a reference counted structure (functions ___set_data_rc and ___data_rc).

Here is an example, assuming cbfn is a Scheme object:

void *callback = ___EXT(___alloc_rc)(0);
if (callback == NULL) out_of_mem();
___EXT(___set_data_rc)(callback, cbfn);

then, to get the value of cbfn (possibly updated by the GC) use:

cbfn = ___EXT(___data_rc)(callback);

and finally, to release the reference counted structure:

___EXT(___release_rc)(callback);

Gambit's FFI uses such reference counted structures when converting from the Scheme to C representation.  So if you pass a Scheme string to a c-lambda expecting a C string, then the pointer received by the C function points to a reference counted structure containing the C string.  The C function can prevent deallocation of the C string by calling ___addref_string (which simply calls ___addref_rc).  This is useful when the C string must outlive the C function that received it (for example, if that string needs to be stored in a table for later use by the C code).

Marc



More information about the Gambit-list mailing list