Implement "TypeLevelReasoning" proposal at wiki:TypeLevelReasoning
[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 __HUGS__
41 import Hugs.IORef
42 #endif
43
44 #ifdef __GLASGOW_HASKELL__
45 import GHC.Base
46 import GHC.STRef
47 import GHC.IORef hiding (atomicModifyIORef)
48 import qualified GHC.IORef
49 #if !defined(__PARALLEL_HASKELL__)
50 import GHC.Weak
51 #endif
52 #endif /* __GLASGOW_HASKELL__ */
53
54 #if defined(__GLASGOW_HASKELL__) && !defined(__PARALLEL_HASKELL__)
55 -- |Make a 'Weak' pointer to an 'IORef', using the second argument as a finalizer
56 -- to run when 'IORef' is garbage-collected
57 mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a))
58 mkWeakIORef r@(IORef (STRef r#)) f = IO $ \s ->
59 case mkWeak# r# r f s of (# s1, w #) -> (# s1, Weak w #)
60 #endif
61
62 -- |Mutate the contents of an 'IORef'.
63 --
64 -- Be warned that 'modifyIORef' does not apply the function strictly. This
65 -- means if the program calls 'modifyIORef' many times, but seldomly uses the
66 -- value, thunks will pile up in memory resulting in a space leak. This is a
67 -- common mistake made when using an IORef as a counter. For example, the
68 -- following will likely produce a stack overflow:
69 --
70 -- >ref <- newIORef 0
71 -- >replicateM_ 1000000 $ modifyIORef ref (+1)
72 -- >readIORef ref >>= print
73 --
74 -- To avoid this problem, use 'modifyIORef'' instead.
75 modifyIORef :: IORef a -> (a -> a) -> IO ()
76 modifyIORef ref f = readIORef ref >>= writeIORef ref . f
77
78 -- |Strict version of 'modifyIORef'
79 modifyIORef' :: IORef a -> (a -> a) -> IO ()
80 modifyIORef' ref f = do
81 x <- readIORef ref
82 let x' = f x
83 x' `seq` writeIORef ref x'
84
85 -- |Atomically modifies the contents of an 'IORef'.
86 --
87 -- This function is useful for using 'IORef' in a safe way in a multithreaded
88 -- program. If you only have one 'IORef', then using 'atomicModifyIORef' to
89 -- access and modify it will prevent race conditions.
90 --
91 -- Extending the atomicity to multiple 'IORef's is problematic, so it
92 -- is recommended that if you need to do anything more complicated
93 -- then using 'Control.Concurrent.MVar.MVar' instead is a good idea.
94 --
95 -- 'atomicModifyIORef' does not apply the function strictly. This is important
96 -- to know even if all you are doing is replacing the value. For example, this
97 -- will leak memory:
98 --
99 -- >ref <- newIORef '1'
100 -- >forever $ atomicModifyIORef ref (\_ -> ('2', ()))
101 --
102 -- Use 'atomicModifyIORef'' or 'atomicWriteIORef' to avoid this problem.
103 --
104 atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
105 #if defined(__GLASGOW_HASKELL__)
106 atomicModifyIORef = GHC.IORef.atomicModifyIORef
107
108 #elif defined(__HUGS__)
109 atomicModifyIORef = plainModifyIORef -- Hugs has no preemption
110 where plainModifyIORef r f = do
111 a <- readIORef r
112 case f a of (a',b) -> writeIORef r a' >> return b
113 #endif
114
115 -- | Strict version of 'atomicModifyIORef'. This forces both the value stored
116 -- in the 'IORef' as well as the value returned.
117 atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
118 atomicModifyIORef' ref f = do
119 b <- atomicModifyIORef ref
120 (\x -> let (a, b) = f x
121 in (a, a `seq` b))
122 b `seq` return b
123
124 -- | Variant of 'writeIORef' with the \"barrier to reordering\" property that
125 -- 'atomicModifyIORef' has.
126 atomicWriteIORef :: IORef a -> a -> IO ()
127 atomicWriteIORef ref a = do
128 x <- atomicModifyIORef ref (\_ -> (a, ()))
129 x `seq` return ()
130
131 {- $memmodel
132
133 In a concurrent program, 'IORef' operations may appear out-of-order
134 to another thread, depending on the memory model of the underlying
135 processor architecture. For example, on x86, loads can move ahead
136 of stores, so in the following example:
137
138 > maybePrint :: IORef Bool -> IORef Bool -> IO ()
139 > maybePrint myRef yourRef = do
140 > writeIORef myRef True
141 > yourVal <- readIORef yourRef
142 > unless yourVal $ putStrLn "critical section"
143 >
144 > main :: IO ()
145 > main = do
146 > r1 <- newIORef False
147 > r2 <- newIORef False
148 > forkIO $ maybePrint r1 r2
149 > forkIO $ maybePrint r2 r1
150 > threadDelay 1000000
151
152 it is possible that the string @"critical section"@ is printed
153 twice, even though there is no interleaving of the operations of the
154 two threads that allows that outcome. The memory model of x86
155 allows 'readIORef' to happen before the earlier 'writeIORef'.
156
157 The implementation is required to ensure that reordering of memory
158 operations cannot cause type-correct code to go wrong. In
159 particular, when inspecting the value read from an 'IORef', the
160 memory writes that created that value must have occurred from the
161 point of view of the current therad.
162
163 'atomicModifyIORef' acts as a barrier to reordering. Multiple
164 'atomicModifyIORef' operations occur in strict program order. An
165 'atomicModifyIORef' is never observed to take place ahead of any
166 earlier (in program order) 'IORef' operations, or after any later
167 'IORef' operations.
168
169 -}
170