Proposed change to ForeignPtr
Manuel M T Chakravarty
chak at cse.unsw.edu.au
Wed Sep 11 05:26:04 EDT 2002
George Russell <ger at tzi.de> wrote,
> 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
> 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?
There are good reasons why the 1.0 version of the FFI
Addendum restricts itself to Haskell <-> C interaction and
not more. The scenario that you sketch is one such reason.
In other words, the kind of functionality that you want is
currently not being supported by the standard FFI.
(Nevertheless, system-specific extensions to the standard in
GHC allow you to implement what you want).
BTW, having two languages with separated heaps interact is a
big mess as soon as you can have cycles, which you usually
cannot exclude. Alastair already pointed that out and
Martin Odersky also has nice stories to tell about this.
More information about the FFI