[plt-scheme] Cooperating with the GC in foreign.ss code
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
> 4.2.1.3; 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