[gambit-list] Allocate Scheme vector before or after C call?

Marc Feeley feeley at iro.umontreal.ca
Sat Jul 18 14:14:20 EDT 2020


Still objects are essentially allocated with malloc (with an extra header and properly aligned), but the allocated bytes are accounted as being part of the “Scheme heap” and if this exceeds the current Scheme heap size the garbage collector is called to free some space (this may call free if some of the still objects are no longer accessible from the Scheme world and their refcount is 0).  Note that the refcount counts the number of references external to the Scheme heap (typically references from the C world).

When control is transferred from Scheme to C (when a c-lambda is called), the garbage collector will only be triggered when control returns to Scheme from C, or when the C code performs an allocation on the Scheme heap (using ___alloc_scmobj, ___make_vector, ___make_pair, a C to Scheme conversion function, etc).  So by carefully writing the C code (avoiding Scheme object allocation) it is possible to guarantee that the GC is not triggered.  When this can’t be avoided, it is important to remember that the GC can move any movable Scheme object (which is the normal allocation strategy for small Scheme objects allocated in Scheme code), but permanent and still objects will not move.  This is the reason why the C allocation functions in for Scheme objects allocate non-movable objects… it makes it possible with no extra bookkeeping to store references to the objects anywhere without concern that a GC will move the objects.

So concerning your question…

Option 1 (malloc temporary buffer in C, and copy it into a Scheme vector) will avoid GC issues, but it is slow (double allocation and copy).

Option 2 (preallocating a buffer in Scheme code and passing it to C) may be problematic when the Scheme buffer is a movable object.  This will require the C code to avoid any additional Scheme object allocation.  This could be circumvented by calling a Scheme allocation procedure that guarantees that the result is a still object.  One way to do this is to call ##still-copy to create a still object that is a copy of its parameter, e.g. (##still-copy (u8vector 1 2 3)).  The ___alloc_scmobj C function could also be called (with suitable interface code).  No special code is needed to have the GC deallocate the object.

Option 3 (allocating buffer in C and “transferring ownership” to Scheme) is possible, but not the way you think.  The end result won’t be a Scheme vector… it will be a foreign object that points to the C buffer.  In a sense this is the cleanest solution as it separates the Scheme and C worlds.  However it makes accessing the contents of the C buffer from Scheme somewhat painful (you need to define your own accessor procedures for this).

I would avoid option 1 and use options 2 and 3 depending on the needs of the application (is the data shared between C and Scheme, or Scheme is just glue code to receive raw data from C and pass it to some other C function).

Marc



> On Jul 18, 2020, at 9:14 AM, Lassi Kortela <lassi at lassi.io> wrote:
> 
> Which of the following is the better strategy for calling C functions that fill a pre-allocated buffer but might fail?
> 
> Option 1. First malloc() a temporary buffer in C, call the desired C function to fill that buffer, and if the C function succeeds then allocate a Scheme string/vector of the same size as the temp buffer and copy the temp buffer into it. If the C function fails, free() the temp buffer and return an error value to Scheme.
> 
> Option 2. First allocate a Scheme string/vector of the right size, then call the desired C function to fill it directly. No temporary buffer is used. If the C function fails, free the Scheme object. (Which function in the Gambit FFI does this?)
> 
> Does GC present complexities for option 2 (especially when interacting threads and/or signals)?
> 
> _______________________________________________
> Gambit-list mailing list
> Gambit-list at iro.umontreal.ca
> https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list
> 





More information about the Gambit-list mailing list