# Proposed change to ForeignPtr

George Russell ger at tzi.de
Tue Sep 10 10:31:17 EDT 2002

Manuel wrote (snipped)

> I have changed this in the spec now.  I attach the wording
> used in the spec.

> \item[newForeignPtr ::\ Ptr a -> FunPtr (Ptr a -> IO ()) -> IO (ForeignPtr a)]
>   Turn a plain memory reference into a foreign object by associating a
>   finalizer with the reference.  The finalizer is represented by a pointer to
>   an external function, which will be executed after the last reference to the
>   foreign object is dropped.  On invocation, the finalizer receives a pointer
>   to the associated foreign object as an argument.  Note that there is no
>   guarantee on how soon the finalizer is executed after the last reference was
>   dropped; this depends on the details of the Haskell storage manager. The
>   only guarantee is that the finalizer runs before the program terminates.
>
>   Whether a finaliser may call back into the Haskell system is system
>   dependent.  Portable code may not rely on such call backs.
>
> \item[addForeignPtrFinalizer ::\ ForeignPtr a -> FunPtr (Ptr a -> IO ()) -> IO
>   ()] Add another finalizer to the given foreign object. No guarantees are
>   made on the order in which multiple finalizers for a single object are run.

I think this is all a rather murky area.  Consider two systems, let's call them
Haskell and Foogle, which both operate heaps and do their own storage allocation,
but also communicate over similar FFIs.  We might very reasonably
have situations where fairly complex  inter-language pointers exist, so for example Haskell holds a
ForeignPtr to something in the Foogle heap; the pointed-to Foogle object in turn references
a Haskell object (presumably provided via StablePtr).  Now suppose Haskell wants to
drop the ForeignPtr.  Then the logical thing for the finalizer to do is to tell Foogle
that Haskell is no longer interested in the Foogle object.  This then gives Foogle
the chance on its own garbage collection to in turn drop the Haskell StablePtr.  In turn
this means somehow running StablePtr.freeStablePtr.  However this scheme I don't know if
that's legal, because the Haskell finalizer you need to run "freeStablePtr" is indirectly
provoked by the initial Haskell finalizer.

This is a pity, because this might actually be a fairly good way of managing garbage collection
between Foogle and Haskell.  Of course you would need at least reference counters (if you can
guarantee there are no cycles containing both languages) or something more powerful otherwise,
but reference counters at least can be provided.  Furthermore I do actually have a real case
in mind where I might use something like this, though I'd rather not go into details at this
time.

I'm afraid I haven't been following this thread lately, so I don't know what the big problem
is about calling Haskell from a finalizer; I suppose it's something to do with us being in the
middle of garbage collection.  However wouldn't it be better to allow finalizers to somehow provide
an action which may call Haskell, but (a) may be performed at some later date (such as when the GC is
over); (b) consequently, may not assume that the pointer finalized still points to anything?