[plt-scheme] ffi and register-finalizer
On May 20, Michael Reynolds wrote:
> For me it does not do this, the destructors are not called. The
> printf runs and the pointer can be used but the destructor is not
> called automatically. I was wondering if anyone has more experience
> with this. Is it supposed to garbage collect your c pointers? If
> not is there a way to make it do that? Or is there some other
> error(s) in what I am trying to do?
Your code seems fine. I used the following C code:
| #include <stdlib.h>
|
| void* make_foo() {
| void *p = malloc(100);
| printf("allocating foo %d\n", p);
| return p;
| }
|
| void free_foo(void *p) {
| printf("de-allocating foo %d\n", p);
| free(p);
| }
and the following Scheme code which is based on your code:
| > (define-cpointer-type _foo #f #f
| (lambda (ptr)
| (if ptr
| (begin (register-finalizer ptr free_foo)
| (printf "Registering ptr\n")
| ptr)
| (error '_foo "got a NULL pointer"))))
| > (define free_foo
| (get-ffi-obj "free_foo" "x.so" (_fun _foo -> _void)))
| > (define make_foo
| (get-ffi-obj "make_foo" "x.so" (_fun -> _foo)))
Using this, things seem to be running fine:
| > (define a (list (make_foo)))
| allocating foo 136969432
| Registering ptr
| > (set! a (cons (make_foo) a))
| allocating foo 136969536
| Registering ptr
| > (set! a (cons (make_foo) a))
| allocating foo 136969640
| Registering ptr
| > (set! a (cons (make_foo) a))
| allocating foo 136969744
| Registering ptr
| > (set! a '())
| > (collect-garbage)
| de-allocating foo 136969432
| de-allocating foo 136969744
| de-allocating foo 136969536
| de-allocating foo 136969640
But make sure that you read the documentation -- this is delicate
stuff...
* If you allocate things in Scheme (or in some extension code that
uses scheme_malloc) then there is no need to use `free'.
* The destructor can be any function which can be registered with any
Scheme object, in fact the whole thing is not tightly related to the
foreign interface and is provided for convenience.
* An implication of this is that you want to register a finalizer only
once with every unique pointer. Otherwise, if there are two Scheme
pointer objects with the same value, then the destructor will be
called twice.
* Two standard solutions are
(a) have a normal _foo pointer type with no finalizer and an
additional _foo* with it, use _foo* only for foreign functions
that create such objects
(b) use a single _foo type with no finalizers, and for functions
that construct such value, add wrapper code that will do the
registration. Like this:
(_fun ... -> (p : _foo)
-> (begin (register-finalizer p free_foo) p))
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!