[Haskell-cafe] Re: Haskell FFI and finalizers

Simon Marlow simonmarhaskell at gmail.com
Tue Oct 9 10:36:13 EDT 2007

Maxime Henrion wrote:
> Stefan O'Rear wrote:
>> On Thu, Oct 04, 2007 at 12:55:41AM +0200, Maxime Henrion wrote:
>>> When writing the binding for foo_new(), I need to open a file with
>>> fopen() to pass it the FILE *.  Then I get a struct foo * that I can
>>> easily associate the the foo_destroy() finalizer.  However, when
>>> finalizing the struct foo * object, I want to also close the FILE *
>>> handle.
>>> If I write a small C function for doing the finalizer myself, I still
>>> wouldn't get passed the FILE * to close, only the struct foo * pointer
>>> which is of no use.
>> Ah, yes, this does make the situation more interesting.
>> Looks like newForeignPtrEnv is maybe what you want?
> Yeah, this is what I use now.  I wrote a player_finalizer() function in
> C, that takes a FILE * and a pointer to the struct I'm handling, and
> which just closes the file.  I then added these sources to the mix in my
> .cabal file (with C-Sources, Extra-Includes, etc), and registered this
> new finalizer using addForeignPtrFinalizerEnv.
> This makes me want to ask you, what is so bad about Foreign.Concurrent
> that it should be avoided at almost any cost?  It sure is likely to be
> much slower than just calling a plain C finalizer, but aren't Haskell
> threads super-cheap anyways?

In GHC ordinary ForeignPtr finalizers are implemented using 
Foreign.Concurrent anyway.  It's not so much that Foreign.Concurrent should 
be avoided at all costs, but rather finalizers in general should be 
avoided, especially if you really care about when they run (i.e. bad things 
could happen if they run late or at unpredictable times).

The Haskell code is not run "by the garbage collector", rather the garbage 
collector figures out which finalizers need running and creates a thread to 
run them.  It's perfectly safe to have C finalizers that invoke Haskell 
code using GHC, although this is explicitly undefined by the FFI spec.

The reason that Foreign.Concurrent is separate from Foreign.ForeignPtr is 
that it does essentially require concurrency to implement, whereas ordinary 
C finalizers can be run by the GC (although GHC doesn't do it this way).


More information about the Haskell-Cafe mailing list