2 % (c) The AQUA Project, Glasgow University, 1994-1996
5 \section[PrelConc]{Module @PrelConc@}
7 Basic concurrency stuff
10 {-# OPTIONS -fno-implicit-prelude #-}
15 ( ThreadId -- abstract
17 -- Forking and suchlike
18 , forkIO -- :: IO () -> IO ThreadId
19 , myThreadId -- :: IO ThreadId
20 , killThread -- :: ThreadId -> IO ()
21 , raiseInThread -- :: ThreadId -> Exception -> IO ()
22 , par -- :: a -> b -> b
23 , fork -- :: a -> b -> b
24 , seq -- :: a -> b -> b
25 {-threadDelay, threadWaitRead, threadWaitWrite,-}
29 , newMVar -- :: a -> IO (MVar a)
30 , newEmptyMVar -- :: IO (MVar a)
31 , takeMVar -- :: MVar a -> IO a
32 , putMVar -- :: MVar a -> a -> IO ()
33 , readMVar -- :: MVar a -> IO a
34 , swapMVar -- :: MVar a -> a -> IO a
35 , isEmptyMVar -- :: MVar a -> IO Bool
40 import PrelErr ( parError, seqError )
41 import PrelST ( liftST )
42 import PrelIOBase ( IO(..), MVar(..), unsafePerformIO )
43 import PrelBase ( Int(..) )
44 import PrelException ( Exception(..), AsyncException(..) )
46 infixr 0 `par`, `fork`
49 %************************************************************************
51 \subsection{@ThreadId@, @par@, and @fork@}
53 %************************************************************************
56 data ThreadId = ThreadId ThreadId#
57 -- ToDo: data ThreadId = ThreadId (Weak ThreadId#)
58 -- But since ThreadId# is unlifted, the Weak type must use open
61 forkIO :: IO () -> IO ThreadId
62 forkIO action = IO $ \ s ->
63 case (fork# action s) of (# s1, id #) -> (# s1, ThreadId id #)
65 killThread :: ThreadId -> IO ()
66 killThread (ThreadId id) = IO $ \ s ->
67 case (killThread# id (AsyncException ThreadKilled) s) of s1 -> (# s1, () #)
69 raiseInThread :: ThreadId -> Exception -> IO ()
70 raiseInThread (ThreadId id) ex = IO $ \ s ->
71 case (killThread# id ex s) of s1 -> (# s1, () #)
73 myThreadId :: IO ThreadId
74 myThreadId = IO $ \s ->
75 case (myThreadId# s) of (# s1, id #) -> (# s1, ThreadId id #)
77 -- "seq" is defined a bit wierdly (see below)
79 -- The reason for the strange "0# -> parError" case is that
80 -- it fools the compiler into thinking that seq is non-strict in
81 -- its second argument (even if it inlines seq at the call site).
82 -- If it thinks seq is strict in "y", then it often evaluates
83 -- "y" before "x", which is totally wrong.
85 -- Just before converting from Core to STG there's a bit of magic
86 -- that recognises the seq# and eliminates the duff case.
90 seq x y = case (seq# x) of { 0# -> seqError; _ -> y }
92 par, fork :: a -> b -> b
96 #if defined(__PARALLEL_HASKELL__) || defined (__GRANSIM__)
97 par x y = case (par# x) of { 0# -> parError; _ -> y }
102 fork x y = unsafePerformIO (forkIO (x `seq` return ())) `seq` y
106 %************************************************************************
108 \subsection[mvars]{M-Structures}
110 %************************************************************************
112 M-Vars are rendezvous points for concurrent threads. They begin
113 empty, and any attempt to read an empty M-Var blocks. When an M-Var
114 is written, a single blocked thread may be freed. Reading an M-Var
115 toggles its state from full back to empty. Therefore, any value
116 written to an M-Var may only be read once. Multiple reads and writes
117 are allowed, but there must be at least one read between any two
121 --Defined in IOBase to avoid cycle: data MVar a = MVar (SynchVar# RealWorld a)
123 instance Eq (MVar a) where
124 (MVar mvar1#) == (MVar mvar2#) = sameMVar# mvar1# mvar2#
126 newEmptyMVar :: IO (MVar a)
128 newEmptyMVar = IO $ \ s# ->
130 (# s2#, svar# #) -> (# s2#, MVar svar# #)
132 takeMVar :: MVar a -> IO a
134 takeMVar (MVar mvar#) = IO $ \ s# -> takeMVar# mvar# s#
136 putMVar :: MVar a -> a -> IO ()
138 putMVar (MVar mvar#) x = IO $ \ s# ->
139 case putMVar# mvar# x s# of
142 newMVar :: a -> IO (MVar a)
145 newEmptyMVar >>= \ mvar ->
146 putMVar mvar value >>
149 readMVar :: MVar a -> IO a
152 takeMVar mvar >>= \ value ->
153 putMVar mvar value >>
156 swapMVar :: MVar a -> a -> IO a
159 takeMVar mvar >>= \ old ->
164 Low-level op. for checking whether an MVar is filled-in or not.
165 Notice that the boolean value returned is just a snapshot of
166 the state of the MVar. By the time you get to react on its result,
167 the MVar may have been filled (or emptied) - so be extremely
168 careful when using this operation.
170 If you can re-work your abstractions to avoid having to
171 depend on isEmptyMVar, then you're encouraged to do so,
172 i.e., consider yourself warned about the imprecision in
173 general of isEmptyMVar :-)
175 isEmptyMVar :: MVar a -> IO Bool
176 isEmptyMVar (MVar mv#) = IO $ \ s# ->
177 case isEmptyMVar# mv# s# of
178 (# s2#, flg #) -> (# s2#, not (flg ==# 0#) #)
182 %************************************************************************
184 \subsection{Thread waiting}
186 %************************************************************************
188 @threadDelay@ delays rescheduling of a thread until the indicated
189 number of microseconds have elapsed. Generally, the microseconds are
190 counted by the context switch timer, which ticks in virtual time;
191 however, when there are no runnable threads, we don't accumulate any
192 virtual time, so we start ticking in real time. (The granularity is
193 the effective resolution of the context switch timer, so it is
194 affected by the RTS -C option.)
196 @threadWaitRead@ delays rescheduling of a thread until input on the
197 specified file descriptor is available for reading (just like select).
198 @threadWaitWrite@ is similar, but for writing on a file descriptor.
202 threadDelay, threadWaitRead, threadWaitWrite :: Int -> IO ()
204 threadDelay (I# x#) = IO $ \ s# ->
208 threadWaitRead (I# x#) = IO $ \ s# ->
209 case waitRead# x# s# of
212 threadWaitWrite (I# x#) = IO $ \ s# ->
213 case waitWrite# x# s# of