content: {-# 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 r@(IORef (STRef r#)) (IO finalizer) = IO $ \s ->
      case mkWeak# r# r finalizer s of (# s1, w #) -> (# s1, Weak 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 ref f = readIORef ref >>= writeIORef ref . 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' ref f = do
      x <- readIORef ref
      let x' = f 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 ref f = do
    (_old, (_new, res)) <- atomicModifyIORef2 ref 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 ref a = do
    _ <- atomicSwapIORef ref a
    pure ()
  
  