On 16/02/2012 22:20, Michael Craig wrote:
 > 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.

If your goal is to add a finalizer to an IORef, I would use Data.IORef.mkWeakIORef. It adds the finalizer to the actual primitive MutVar# object inside the IORef, so it's a lot more predictable (the primitive object can't be copied under your feet).

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

No kidding!

Finalizers on ordinary Haskell objects are very limited in usefulness, the only good use I've found is for memo tables.

Cheers,
        Simon




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

Mike Craig



On Thu, Feb 16, 2012 at 4:15 PM, Ian Lynagh <ig...@earth.li
<mailto:ig...@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
    <mailto:Glasgow-haskell-users@haskell.org>
    http://www.haskell.org/mailman/listinfo/glasgow-haskell-users




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


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

Reply via email to