Fail: <<loop>> from finalizers and stuff
simonmar at microsoft.com
Mon Jul 5 06:38:05 EDT 2004
On 04 July 2004 23:54, Sven Moritz Hallberg wrote:
> Dear Foreign Function Interface,
> why does a program like the following fail with a "<<loop>>" exception
> (using GHC 6.2 on MacOS X)?
> import Foreign
> main =
> f <- mkFinPtr finalizer
> fp <- newForeignPtr f nullPtr
> putStrLn "Hello World"
> finalizer ptr = putStrLn ("Finalize "++show ptr++".")
> foreign import ccall "wrapper"
> mkFinPtr :: (Ptr () -> IO ()) -> IO (FinalizerPtr ())
This is a FAQ, but you could be forgiven because the latest version of
the FAQ on the web site doesn't have this entry yet. Here it is:
<term>I can't get finalizers to work properly. My program
sometimes just prints
<para>Chances are that your program is trying to write a
message to <literal>stdout</literal> or
<literal>stderr</literal> in the finalizer. Handles have
finalizers themselves, and since finalizers don't keep other
finalized values alive, the <literal>stdout</literal> and
<literal>stderr</literal> Handles may be finalized before your
finalizer runs. If this happens, your finalizer will block on
the handle, and probably end up receiving a
<literal>NonTermination</literal> exception (which is printed
> Also, does the use of a "wrapper" import constitute a callback from C
> in the sense of the following statement?
> "Whether a finalizer may call back into the Haskell system is
> dependent. Portable code may not rely on such callbacks."
> I.e. is the above code non-portable?
> Why is the ForeignPtr interface constrained to finalizers that are
> FunPtrs at all? I want to touch a ForeignPtr from another's finalizer
> to satisfy a liveness dependency (as suggested in the spec). What is
> the best way to do this?
Good point. That comment in the spec is left over from when we had
Haskell finalizers in the standard, and doesn't make sense any more.
(Manuel - are you keeping errata somewhere? Or is someone else?)
Doing this is now non-portable because some Haskell systems don't
support calling back into Haskell from a finalizer. If you're committed
to being non-portable, then the right way is to use the
Foreign.Concurrent interface instead of the wrapper trick you use above.
More information about the FFI