{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE UnboxedTuples #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.Internal.Data.IORef
-- Copyright   :  (c) The University of Glasgow 2001
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  stable
-- Portability :  portable
--
-- Mutable references in the IO monad.
--
-----------------------------------------------------------------------------

module GHC.Internal.Data.IORef
  (
        -- * IORefs
        IORef,                -- abstract, instance of: Eq, Typeable
        newIORef,
        readIORef,
        writeIORef,
        modifyIORef,
        modifyIORef',
        atomicModifyIORef,
        atomicModifyIORef',
        atomicWriteIORef,
        mkWeakIORef,
        ) where

import GHC.Internal.Base
import GHC.Internal.STRef
import GHC.Internal.IORef
import GHC.Internal.Weak

-- |Make a 'Weak' pointer to an 'IORef', using the second argument as a finalizer
-- to run when 'IORef' is garbage-collected
mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a))
mkWeakIORef :: forall a. IORef a -> IO () -> IO (Weak (IORef a))
mkWeakIORef r :: IORef a
r@(IORef (STRef MutVar# RealWorld a
r#)) (IO State# RealWorld -> (# State# RealWorld, () #)
finalizer) = (State# RealWorld -> (# State# RealWorld, Weak (IORef a) #))
-> IO (Weak (IORef a))
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, Weak (IORef a) #))
 -> IO (Weak (IORef a)))
-> (State# RealWorld -> (# State# RealWorld, Weak (IORef a) #))
-> IO (Weak (IORef a))
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s ->
    case MutVar# RealWorld a
-> IORef a
-> (State# RealWorld -> (# State# RealWorld, () #))
-> State# RealWorld
-> (# State# RealWorld, Weak# (IORef a) #)
forall a b c.
a
-> b
-> (State# RealWorld -> (# State# RealWorld, c #))
-> State# RealWorld
-> (# State# RealWorld, Weak# b #)
mkWeak# MutVar# RealWorld a
r# IORef a
r State# RealWorld -> (# State# RealWorld, () #)
finalizer State# RealWorld
s of (# State# RealWorld
s1, Weak# (IORef a)
w #) -> (# State# RealWorld
s1, Weak# (IORef a) -> Weak (IORef a)
forall v. Weak# v -> Weak v
Weak Weak# (IORef a)
w #)

-- |Mutate the contents of an 'IORef', combining 'readIORef' and 'writeIORef'.
-- This is not an atomic update, consider using 'atomicModifyIORef' when
-- operating in a multithreaded environment.
--
-- Be warned that 'modifyIORef' does not apply the function strictly.  This
-- means if the program calls 'modifyIORef' many times, but seldom uses the
-- value, thunks will pile up in memory resulting in a space leak.  This is a
-- common mistake made when using an IORef as a counter.  For example, the
-- following will likely produce a stack overflow:
--
-- >ref <- newIORef 0
-- >replicateM_ 1000000 $ modifyIORef ref (+1)
-- >readIORef ref >>= print
--
-- To avoid this problem, use 'modifyIORef'' instead.
modifyIORef :: IORef a -> (a -> a) -> IO ()
modifyIORef :: forall a. IORef a -> (a -> a) -> IO ()
modifyIORef IORef a
ref a -> a
f = IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
ref IO a -> (a -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef a
ref (a -> IO ()) -> (a -> a) -> a -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
f

-- |Strict version of 'modifyIORef'.
-- This is not an atomic update, consider using 'atomicModifyIORef'' when
-- operating in a multithreaded environment.
--
-- @since base-4.6.0.0
modifyIORef' :: IORef a -> (a -> a) -> IO ()
modifyIORef' :: forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef a
ref a -> a
f = do
    x <- IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
ref
    let x' = a -> a
f a
x
    x' `seq` writeIORef ref x'

-- |Atomically modifies the contents of an 'IORef'.
--
-- This function is useful for using 'IORef' in a safe way in a multithreaded
-- program.  If you only have one 'IORef', then using 'atomicModifyIORef' to
-- access and modify it will prevent race conditions.
--
-- Extending the atomicity to multiple 'IORef's is problematic, so it
-- is recommended that if you need to do anything more complicated
-- then using 'Control.Concurrent.MVar.MVar' instead is a good idea.
--
-- Conceptually,
--
-- @
-- atomicModifyIORef ref f = do
--   -- Begin atomic block
--   old <- 'readIORef' ref
--   let r = f old
--       new = fst r
--   'writeIORef' ref new
--   -- End atomic block
--   case r of
--     (_new, res) -> pure res
-- @
--
-- The actions in the section labeled \"atomic block\" are not subject to
-- interference from other threads. In particular, it is impossible for the
-- value in the 'IORef' to change between the 'readIORef' and 'writeIORef'
-- invocations.
--
-- The user-supplied function is applied to the value stored in the 'IORef',
-- yielding a new value to store in the 'IORef' and a value to return. After
-- the new value is (lazily) stored in the 'IORef', @atomicModifyIORef@ forces
-- the result pair, but does not force either component of the result. To force
-- /both/ components, use 'atomicModifyIORef''.
--
-- Note that
--
-- @atomicModifyIORef ref (\_ -> undefined)@
--
-- will raise an exception in the calling thread, but will /also/
-- install the bottoming value in the 'IORef', where it may be read by
-- other threads.
--
-- This function imposes a memory barrier, preventing reordering around the
-- \"atomic block\"; see "Data.IORef#memmodel" for details.
--
atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
atomicModifyIORef :: forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef a
ref a -> (a, b)
f = do
  (_old, (_new, res)) <- IORef a -> (a -> (a, b)) -> IO (a, (a, b))
forall a b. IORef a -> (a -> (a, b)) -> IO (a, (a, b))
atomicModifyIORef2 IORef a
ref a -> (a, b)
f
  pure res

-- | Variant of 'writeIORef'. The prefix "atomic" relates to a fact that
-- it imposes a reordering barrier, similar to 'atomicModifyIORef'.
-- Such a write will not be reordered with other reads
-- or writes even on CPUs with weak memory model.
--
-- @since base-4.6.0.0
atomicWriteIORef :: IORef a -> a -> IO ()
atomicWriteIORef :: forall a. IORef a -> a -> IO ()
atomicWriteIORef IORef a
ref a
a = do
  _ <- IORef a -> a -> IO a
forall a. IORef a -> a -> IO a
atomicSwapIORef IORef a
ref a
a
  pure ()