I haven't checked, but ...

I checked, and your solution works. In the context of a larger program, getting NOLINE pragmas in all the right places would be challenging, wouldn't it?

I found a bug report on the GHC Trac [1] in which Simon explains the importance of evaluating the thunk before calling addFinalizer. (Otherwise the finalizer is added to the thunk.) This works:

newThing :: IO Thing
newThing = do
  x <- Thing `fmap` newIORef True
  return $ unsafePerformIO ( do
    x' <- evaluate x
    addFinalizer x' $ putStrLn "running finalizer" ) `seq` x

If anyone can show me how to get rid of unsafePerformIO in there, that'd be great. Tried a few things to no avail.

Finalizers are tricky things, especially when combined with some of
> GHC's optimisations.

No kidding!

[1] http://hackage.haskell.org/trac/ghc/ticket/5365

Mike Craig



On Thu, Feb 16, 2012 at 4:15 PM, Ian Lynagh <igloo@earth.li> wrote:
On Thu, Feb 16, 2012 at 02:55:13PM -0600, Austin Seipp wrote:
> 64-bit GHC on OS X gives me this:
>
> $ ghc -fforce-recomp -threaded finalizer
> [1 of 1] Compiling Main             ( finalizer.hs, finalizer.o )
> Linking finalizer ...
> $ ./finalizer
> waiting ...
> done!
> waiting ...
> running finalizer
> done!
>
> However, it's a different story when `-O2` is specified:
>
> $ ghc -O2 -fforce-recomp -threaded finalizer
> [1 of 1] Compiling Main             ( finalizer.hs, finalizer.o )
> Linking finalizer ...
> $ ./finalizer
> waiting ...
> running finalizer
> done!
> waiting ...
> done!
>
> This smells like a bug. The stranger thing is that the GC will run the
> finalizer, but it doesn't reclaim the object? I'd think `readIORef`
> going after an invalidated pointer the GC reclaimed would almost
> certainly crash.

The finalizer is attached to the Thing, not the IORef. I haven't
checked, but I assume that ioref gets inlined, so effectively (ioref x)
is evaluated early. If you change it to

   readIORef (ioref' x) >>= \ix -> ix `seq` return ()

and define

   {-# NOINLINE ioref' #-}
   ioref' :: Thing -> IORef Bool
   ioref' = ioref

then you'll get the sort of output you expect.

Finalizers are tricky things, especially when combined with some of
GHC's optimisations.


Thanks
Ian


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users