ghc-internal-9.1001.0: src/GHC/Internal/Data/IORef.hs
{-# 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 ()