[Haskell-cafe] Re: how to implement daemon start and stop directives?

Ertugrul Soeylemez es at ertes.de
Fri Jan 23 10:15:00 EST 2009

Eugene Kirpichov <ekirpichov at gmail.com> wrote:

> >> daemon :: IO () -> IO (IO ())
> >> daemon action = do
> >>     stopvar <- newIORef False
> >>     let run = do
> >>           stop <- readIORef stopvar
> >>           if stop then return () else (action >> run)
> >>     forkIO run
> >>     return (writeIORef stopvar True)
> >
> > In this case, it's simply a coincidence that it's safe.  It's
> > because you're using an IORef Bool, and because writes to a Bool
> > variable are atomic on virtually all platforms.  An Integer may
> > already fail to be thread-safe.  You need more care and the payoff
> > is zero.  If you still insist on using IORefs, at least use the
> > atomic function above, but that destroys the little performance
> > benefit of using IORefs, unless GHC does some intelligent
> > optimization here, which I doubt.
> This would be the case if the IORef was unboxed, but it is boxed, so
> writing an IORef is actually writing a pointer to a thunk; here, Bool
> and Integer have no difference at all. However, I don't know whether
> GHC makes pointer writes atomic on all platforms (Java does, so it's
> at least doable).

It will likely work, but the compiler is not required to make pointer
writes atomic, and it would be an enormous performance hit.  The pointer
write is more likely atomic by platform, not by the code, but even there
I would be very careful, because it may be not the case for SMP systems.
And you know what happens, when a pointer race condition occurs.

The selection between MVar and IORef is essentially a "security or
performance" question.  Especially for daemons I would rather choose
security.  MVar gives you that security with _the same amount of code_.

And to prove that IORefs do lead to a pointer race condition and hence
are insecure, try the following code:

  main :: IO ()
  main = do
    ref <- newIORef False
    forkIO $ forever $ modifyIORef ref not
    forever $ readIORef ref >>= print

It crashes for me.  I'm using GHC 6.10.1 on an Athlon 64 X2 (32 bits
system).  The error message reads:

  test: internal error: schedule: invalid what_next field
      (GHC version 6.10.1 for i386_unknown_linux)
      Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug


nightmare = unsafePerformIO (getWrongWife >>= sex)

More information about the Haskell-Cafe mailing list