Running a "final" finaliser

Adrian Hey ahey at iee.org
Tue Dec 23 07:22:59 EST 2003


On Monday 22 Dec 2003 10:13 am, Simon Marlow wrote:
> > Thanks for your reply. I'm afraid it's left me even
> > more confused about which way to go with this :-(
> >
> > If it's possible that future Haskell FFI's don't guarantee
> > that all finalisers are run then this more or less rules
> > out the use of the reference counting solution (which
> > wasn't particularly attractive anyway because it needs to
> > be done in C AFAICS :-). If users who want this behaviour
> > are required to code it themselves, it seems to require that
> > they maintain a global list of all allocated ForeignPtrs.
> > But doing that naively will stop them being garbage collected
> > at all, unless it's possible to do something clever using weak
> > pointers. Perhaps it is possible (or maybe some tricks at the
> > C level could be used) but I think it's a significant extra
> > burden for FFI users.
>
> Yes, it would have to be a global list of weak pointers to ForeignPtrs.
> This topic has come up before, though not on this list.  See this
> message, and the rest of the thread:
>
> http://www.haskell.org/pipermail/cvs-ghc/2003-January/016651.html
>
> the thread also moved on to ffi at haskell.org:
>
> http://www.haskell.org/pipermail/ffi/2003-January/001041.html
>
> and be sure to check out the paper by Hans Boehm referenced in that
> message, it's a good summary of the issues involved.

Thanks, I'll take a look at the Boehm paper. I didn't keep up with
this discussion at the time, but now I see the relevance. 

Assuming the weak pointers solution is the way to go, I've been
re-aquainting myself with System.Mem.Weak and now I'm now wondering
what is an appropriate key for each ForeignPtr.

Would it be OK to use the ForeignPtr itself as it's own key?
(Seems OK to me, but this is a bit different from the memoisation
example so I thought I'd check.)

If so, then I guess the thing to do is to maintain a mutable doubly
linked list of Weak pointers to ForeignPtrs using IORef's and have
the finaliser for each weak pointer "short out" the corresponding
list cell. When the program terminates execute the finalisers
of all ForeignPtrs which remain in this list.

Hmm, this is getting awfully complicated, and I still have my
doubts about it for a couple of reasons..

1- Executing ForeignPtr finalisers directly (as in Krasimirs
   example) seems to be ghc specific.
2- If there is no guarantee whether or when ForeignPtr finalisers
   are run then it seems that it is possible that a Weak pointer
   finaliser has been run (thereby deleting the weak pointer
   reference from the list), but the corresponding ForeignPtr
   finaliser has *not* been run.

The solution to problem 2 would seem to be to not associate
any finaliser with with the ForeignPtr, but do all finalisation
in the Weak pointer finaliser. I guess that would cure problem
1 too.

What do folk think about this?   

> performGC doesn't do anything that you can rely on :-)

Oh, that's handy :-)

> > Also, I could you explain what you mean by a suitable
> > exception handler? I don't really understand this at all.
> > I'd expected I may well end up using bracket or similar,
> > but I'm not sure how exception handling is relevant to
> > this problem.
>
> Start your program something like this:
>
>   import Control.Exception (finally)
>
>   main = my_main `finally` clean_up
>   my_main = ... put your program here ...
>   clean_up = ... all the cleanup code goes here ...
>
> You can additionally use finalizers to perform incremental cleanup
> during program execution, but the right way to clean up at the end is to
> use an exception handler as above.

Ah OK, I was hoping the whole thing would be something as simple
as this..

withLibXYX :: IO () -> IO ()
withLibXYZ doit = finally (initialiseLibXYZ >> doit)
                          (performGC >> shutdownLibXYZ)

Where initialiseLibXYZ and shutdownLibXYZ are simple foreign functions
imported from libXYZ. I think it's a real shame performGC or some other
similar function can't simply guarantee that all (garbage) ForeignPtr
finalisers have been run before calling shutdownLibXYZ :-(

Regards
--
Adrian Hey






More information about the Glasgow-haskell-users mailing list