Remove Hugs98 specific code
[packages/base.git] / Data / IORef.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE CPP, NoImplicitPrelude, MagicHash, UnboxedTuples #-}
3
4 -----------------------------------------------------------------------------
5 -- |
6 -- Module : Data.IORef
7 -- Copyright : (c) The University of Glasgow 2001
8 -- License : BSD-style (see the file libraries/base/LICENSE)
9 --
10 -- Maintainer : libraries@haskell.org
11 -- Stability : experimental
12 -- Portability : portable
13 --
14 -- Mutable references in the IO monad.
15 --
16 -----------------------------------------------------------------------------
17
18 module Data.IORef
19 (
20 -- * IORefs
21 IORef, -- abstract, instance of: Eq, Typeable
22 newIORef,
23 readIORef,
24 writeIORef,
25 modifyIORef,
26 modifyIORef',
27 atomicModifyIORef,
28 atomicModifyIORef',
29 atomicWriteIORef,
30
31 #if !defined(__PARALLEL_HASKELL__) && defined(__GLASGOW_HASKELL__)
32 mkWeakIORef,
33 #endif
34 -- ** Memory Model
35
36 -- $memmodel
37
38 ) where
39
40 #ifdef __GLASGOW_HASKELL__
41 import GHC.Base
42 import GHC.STRef
43 import GHC.IORef hiding (atomicModifyIORef)
44 import qualified GHC.IORef
45 #if !defined(__PARALLEL_HASKELL__)
46 import GHC.Weak
47 #endif
48 #endif /* __GLASGOW_HASKELL__ */
49
50 #if defined(__GLASGOW_HASKELL__) && !defined(__PARALLEL_HASKELL__)
51 -- |Make a 'Weak' pointer to an 'IORef', using the second argument as a finalizer
52 -- to run when 'IORef' is garbage-collected
53 mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a))
54 mkWeakIORef r@(IORef (STRef r#)) f = IO $ \s ->
55 case mkWeak# r# r f s of (# s1, w #) -> (# s1, Weak w #)
56 #endif
57
58 -- |Mutate the contents of an 'IORef'.
59 --
60 -- Be warned that 'modifyIORef' does not apply the function strictly. This
61 -- means if the program calls 'modifyIORef' many times, but seldomly uses the
62 -- value, thunks will pile up in memory resulting in a space leak. This is a
63 -- common mistake made when using an IORef as a counter. For example, the
64 -- following will likely produce a stack overflow:
65 --
66 -- >ref <- newIORef 0
67 -- >replicateM_ 1000000 $ modifyIORef ref (+1)
68 -- >readIORef ref >>= print
69 --
70 -- To avoid this problem, use 'modifyIORef'' instead.
71 modifyIORef :: IORef a -> (a -> a) -> IO ()
72 modifyIORef ref f = readIORef ref >>= writeIORef ref . f
73
74 -- |Strict version of 'modifyIORef'
75 modifyIORef' :: IORef a -> (a -> a) -> IO ()
76 modifyIORef' ref f = do
77 x <- readIORef ref
78 let x' = f x
79 x' `seq` writeIORef ref x'
80
81 -- |Atomically modifies the contents of an 'IORef'.
82 --
83 -- This function is useful for using 'IORef' in a safe way in a multithreaded
84 -- program. If you only have one 'IORef', then using 'atomicModifyIORef' to
85 -- access and modify it will prevent race conditions.
86 --
87 -- Extending the atomicity to multiple 'IORef's is problematic, so it
88 -- is recommended that if you need to do anything more complicated
89 -- then using 'Control.Concurrent.MVar.MVar' instead is a good idea.
90 --
91 -- 'atomicModifyIORef' does not apply the function strictly. This is important
92 -- to know even if all you are doing is replacing the value. For example, this
93 -- will leak memory:
94 --
95 -- >ref <- newIORef '1'
96 -- >forever $ atomicModifyIORef ref (\_ -> ('2', ()))
97 --
98 -- Use 'atomicModifyIORef'' or 'atomicWriteIORef' to avoid this problem.
99 --
100 atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
101 #ifdef __GLASGOW_HASKELL__
102 atomicModifyIORef = GHC.IORef.atomicModifyIORef
103 #endif
104
105 -- | Strict version of 'atomicModifyIORef'. This forces both the value stored
106 -- in the 'IORef' as well as the value returned.
107 atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
108 atomicModifyIORef' ref f = do
109 b <- atomicModifyIORef ref
110 (\x -> let (a, b) = f x
111 in (a, a `seq` b))
112 b `seq` return b
113
114 -- | Variant of 'writeIORef' with the \"barrier to reordering\" property that
115 -- 'atomicModifyIORef' has.
116 atomicWriteIORef :: IORef a -> a -> IO ()
117 atomicWriteIORef ref a = do
118 x <- atomicModifyIORef ref (\_ -> (a, ()))
119 x `seq` return ()
120
121 {- $memmodel
122
123 In a concurrent program, 'IORef' operations may appear out-of-order
124 to another thread, depending on the memory model of the underlying
125 processor architecture. For example, on x86, loads can move ahead
126 of stores, so in the following example:
127
128 > maybePrint :: IORef Bool -> IORef Bool -> IO ()
129 > maybePrint myRef yourRef = do
130 > writeIORef myRef True
131 > yourVal <- readIORef yourRef
132 > unless yourVal $ putStrLn "critical section"
133 >
134 > main :: IO ()
135 > main = do
136 > r1 <- newIORef False
137 > r2 <- newIORef False
138 > forkIO $ maybePrint r1 r2
139 > forkIO $ maybePrint r2 r1
140 > threadDelay 1000000
141
142 it is possible that the string @"critical section"@ is printed
143 twice, even though there is no interleaving of the operations of the
144 two threads that allows that outcome. The memory model of x86
145 allows 'readIORef' to happen before the earlier 'writeIORef'.
146
147 The implementation is required to ensure that reordering of memory
148 operations cannot cause type-correct code to go wrong. In
149 particular, when inspecting the value read from an 'IORef', the
150 memory writes that created that value must have occurred from the
151 point of view of the current therad.
152
153 'atomicModifyIORef' acts as a barrier to reordering. Multiple
154 'atomicModifyIORef' operations occur in strict program order. An
155 'atomicModifyIORef' is never observed to take place ahead of any
156 earlier (in program order) 'IORef' operations, or after any later
157 'IORef' operations.
158
159 -}
160