[plt-scheme] FFI - garbage collection

From: Eli Barzilay (eli at barzilay.org)
Date: Tue Oct 11 21:32:46 EDT 2005

On Oct 12, Yoav Goldberg wrote:
> Hi.
> I am wrapping a dll using the v299 ffi.
> As a part of my code, I have a c function that returns a pointer to
> a structure:
> 
> (define-syntax defmshare
>   (syntax-rules ()
>      ((defmshare scheme-name libname type ...)
>       (define scheme-name (get-ffi-obj libname mshare (type ...))))))
> 
> (defmshare MidiNewEv* "MidiNewEv" _fun _short -> _TMidiEv-pointer)

(Ugh, if you went all the way to a macro, why not make the macro add
the _fun?  Otherwise it doesn't do much, and actually looks clearer
with the parens.)


> I want to make sure the memory allocated by the "MidiNewEv" function
> will be freed by GC,  and from what I understand, I need to use
> "register-finalizaer", like so:
> 
> (defmshare MidiFreeEv "MidiFreeEv" _fun _TMidiEv-pointer -> _TMidiEv-pointer)
> 
> (define MidiNewEv ;; make sure chan/port/date are initialized to a default
>   (lambda (type)
>     (let ((ev (MidiNewEv* type)))
>       (chan! ev 0)
>       (port! ev 0)
>       (date! ev 0)
>       (register-finalizer ev MidiFreeEv)
>       ev)))
> 
> I hope I got it right until now, let me know if I got something wrong.

Looks fine.  You could do it by creating a new type that will do the
setting and the finalizer.


> But now comes the trickey part.
> 
> There is another C function:
> (defmshare MidiSendIm "MidiSendIm" _fun _short _TMidiEv-pointer -> _void)
> 
> Which FREES any _TMidiEv-pointer passed to it.
> 
> As far as I understand this is a problem, since that pointer is
> still registered with the finalizer for GC!
> 
> How can I fix this? Is there a way to "un-register" a finalizer, so
> that I could do something like:
> (define GoodMidiSendIm
>    (lambda (n ev)
>         (unregister-finalizer ev) (MidiSendIm n ev)))
> ??

There is no way to do this now (the implementation uses will
executors).  But the problem here seems to be that you *don't* want
automatic freeing of these objects because of the way they are
managed.  Instead, you have to do the manual thing and knwo which
TMidiEv's need to be freed.

Perhaps the library is meant to be used in a way that you never create
these objects unless you send them?  This means that another way to
organize things is to have some Scheme objects that stand for these
TMidiEv objects -- then, you do a wrapper for MidiSendIm that will get
one of these Scheme objects, generate a real TMidiEv object,
initialize it, and immediately send it over to MidiSendIm.

One thing you have to be aware of, is that allocation using the Scheme
`malloc' goes through the GC by default.  I don't think that it will
be a good idea to pass such objects to a C library that will try to
free them...

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!


Posted on the users mailing list.