Re: Help me grok addFinalizer

2012-02-17 Thread Simon Marlow

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


Help me grok addFinalizer

2012-02-16 Thread Michael Craig
When I read the docs for System.Mem.Weak, it all seems to make sense. But
then this code doesn't run as I expect it to when I turn on -threaded:
http://hpaste.org/63832 (Expected/actual output are listed in the paste.)

I've tried this on 7.4.1 and 7.0.4 with the same results. Can someone
enlighten me?

Cheers,
Mike Craig
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Help me grok addFinalizer

2012-02-16 Thread Antoine Latter
On Thu, Feb 16, 2012 at 2:04 PM, Michael Craig mks...@gmail.com wrote:
 When I read the docs for System.Mem.Weak, it all seems to make sense. But
 then this code doesn't run as I expect it to when I turn on
 -threaded: http://hpaste.org/63832 (Expected/actual output are listed in the
 paste.)

 I've tried this on 7.4.1 and 7.0.4 with the same results. Can someone
 enlighten me?


First off, I'm pretty sure finalizers won't run until the data they
were associated with has been GCd, and GHC doesn't do GCs unless there
is allocation - threadDelay doesn't allocate much, I imagine.

Also, from the docs:


A weak pointer may also have a finalizer of type IO (); if it does,
then the finalizer will be run at most once, at a time after the key
has become unreachable by the program (dead). The storage manager
attempts to run the finalizer(s) for an object soon after the object
dies, but promptness is not guaranteed.

It is not guaranteed that a finalizer will eventually run, and no
attempt is made to run outstanding finalizers when the program exits.
Therefore finalizers should not be relied on to clean up resources -
other methods (eg. exception handlers) should be employed, possibly in
addition to finalisers.


Antoine

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


Re: Help me grok addFinalizer

2012-02-16 Thread wagnerdm

Quoting Antoine Latter aslat...@gmail.com:


On Thu, Feb 16, 2012 at 2:04 PM, Michael Craig mks...@gmail.com wrote:

When I read the docs for System.Mem.Weak, it all seems to make sense. But
then this code doesn't run as I expect it to when I turn on
-threaded: http://hpaste.org/63832 (Expected/actual output are listed in the
paste.)

I've tried this on 7.4.1 and 7.0.4 with the same results. Can someone
enlighten me?


First off, I'm pretty sure finalizers won't run until the data they
were associated with has been GCd, and GHC doesn't do GCs unless there
is allocation - threadDelay doesn't allocate much, I imagine.


This seems to be an explanation of why a finalizer might run later  
than expected (or not run at all). But his paste shows that it runs  
*earlier* than what he expected.


~d

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


Re: Help me grok addFinalizer

2012-02-16 Thread Michael Craig
 This seems to be an explanation of why a finalizer might run later than
expected (or not run at all). But his paste shows that it runs *earlier*
than what he expected.

What he said.

 64-bit GHC on OS X gives me this:

 ...

 However, it's a different story when `-O2` is specified:

 ...

You're right. I was compiling with cabal and had -O turned on without
knowing it. So this looks like an optimization bug?

Mike Craig



On Thu, Feb 16, 2012 at 3:55 PM, Austin Seipp mad@gmail.com 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.

 On Thu, Feb 16, 2012 at 2:04 PM, Michael Craig mks...@gmail.com wrote:
  When I read the docs for System.Mem.Weak, it all seems to make sense. But
  then this code doesn't run as I expect it to when I turn on
  -threaded: http://hpaste.org/63832 (Expected/actual output are listed
 in the
  paste.)
 
  I've tried this on 7.4.1 and 7.0.4 with the same results. Can someone
  enlighten me?
 
  Cheers,
  Mike Craig
 
 
  ___
  Glasgow-haskell-users mailing list
  Glasgow-haskell-users@haskell.org
  http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
 



 --
 Regards,
 Austin

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


Re: Help me grok addFinalizer

2012-02-16 Thread Ian Lynagh
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


Re: Help me grok addFinalizer

2012-02-16 Thread Michael Craig
 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 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
 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