[plt-scheme] Cooperating with the GC in foreign.ss code

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Sep 9 07:27:54 EDT 2009

Actually, the pointer in the struct isn't changed when the `data' block
is relocated/reclaimed by the GC. The `make-' for a cstruct allocates
atomic memory (i.e., memory that is assumed to contain no pointers to
GC-managed memory).

The FFI doesn't offer a direct way to specify the layout of an object
and have the GC traverse specific fields of the object. The C-level API
provides scheme_make_type() and GC_register_traversers(), which you can
use to allocate a new type tag and provide GC-traversal functions for
instances using the tag --- but the layout must start with a
`Scheme_Object' block, which includes the type tag. You probably don't
want to go that direction.

Assuming that you need the specific layout of `_gsl_matrix' (otherwise
you'd just use `define-struct'), the best strategy is probably to
allocate the `data' field with 'raw and release it through a finalizer
on each `_gsl_matrix' instance.

At Wed, 9 Sep 2009 10:31:56 +0100, Noel Welsh wrote:
> Hi all,
> I'm wrapping a C struct that contains a pointer to a user allocated
> block of memory. When a GC takes places, this pointer is changed to
> point to a new location, but the values it points to are not copied to
> that location. At least that is what I assume is taking place; the
> observable effect is that the same values are not read back when
> dereferencing the pointer. The example below illustrates the problem.
> How should I fix this so that values survive across a GC? This is in
>; I'll upgrade if necessary.
> Thanks,
> N.
> #lang scheme
> (require
>  scheme/foreign
>  (planet schematics/schemeunit:3))
> (unsafe!)
> (define _size_t _int)
> (define-cstruct _gsl_matrix
>   ([rows  _size_t]
>    [cols  _size_t]
>    [tda   _size_t]
>    [data  _pointer]
>    [block _pointer]
>    [owner _int]))
> (define (gsl_matrix-malloc r c)
>   (define ptr (malloc _double (* r c)))
>   (define m (make-gsl_matrix r c c ptr #f 0))
>   m)
> (define make-matrix gsl_matrix-malloc)
> (define (matrix-ref m r c)
>   (define rows (gsl_matrix-rows m))
>   (define cols (gsl_matrix-cols m))
>   (define idx (+ (* r cols) c))
>   (ptr-ref (gsl_matrix-data m) _double idx))
> (define (matrix-set! m r c val)
>   (define rows (gsl_matrix-rows m))
>   (define cols (gsl_matrix-cols m))
>   (define idx (+ (* r cols) c))
>   (ptr-set! (gsl_matrix-data m) _double idx val))
> (define m (make-matrix 4 4))
> ;; Set an element to known value and check it has that value
> (matrix-set! m 1 1 3.0)
> (check-= (matrix-ref m 1 1) 3.0 0)
> ;; Do some work, necessitating a GC
> (for ([i (in-range 10000)])
>      (make-vector i))
> ;; See if the value survives across a GC (it shouldn't)
> (check-= (matrix-ref m 1 1) 3.0 0)
> _________________________________________________
>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme

Posted on the users mailing list.