2 % (c) The AQUA Project, Glasgow University, 1994-1996
5 \section[PrelConc]{Module @PrelConc@}
7 Basic concurrency stuff
10 {-# OPTIONS -fno-implicit-prelude #-}
15 -- Forking and suchlike
16 , myThreadId -- :: IO ThreadId
17 , killThread -- :: ThreadId -> IO ()
18 , raiseInThread -- :: ThreadId -> Exception -> IO ()
19 , par -- :: a -> b -> b
20 , seq -- :: a -> b -> b
23 {-threadDelay, threadWaitRead, threadWaitWrite,-}
27 , newMVar -- :: a -> IO (MVar a)
28 , newEmptyMVar -- :: IO (MVar a)
29 , takeMVar -- :: MVar a -> IO a
30 , putMVar -- :: MVar a -> a -> IO ()
31 , readMVar -- :: MVar a -> IO a
32 , swapMVar -- :: MVar a -> a -> IO a
33 , isEmptyMVar -- :: MVar a -> IO Bool
38 import PrelErr ( parError, seqError )
39 import PrelST ( liftST )
40 import PrelIOBase ( IO(..), MVar(..), unsafePerformIO )
41 import PrelBase ( Int(..) )
42 import PrelException ( Exception(..), AsyncException(..) )
47 %************************************************************************
49 \subsection{@ThreadId@, @par@, and @fork@}
51 %************************************************************************
54 data ThreadId = ThreadId ThreadId#
55 -- ToDo: data ThreadId = ThreadId (Weak ThreadId#)
56 -- But since ThreadId# is unlifted, the Weak type must use open
59 --forkIO has now been hoisted out into the concurrent library.
61 killThread :: ThreadId -> IO ()
62 killThread (ThreadId id) = IO $ \ s ->
63 case (killThread# id (AsyncException ThreadKilled) s) of s1 -> (# s1, () #)
65 raiseInThread :: ThreadId -> Exception -> IO ()
66 raiseInThread (ThreadId id) ex = IO $ \ s ->
67 case (killThread# id ex s) of s1 -> (# s1, () #)
69 myThreadId :: IO ThreadId
70 myThreadId = IO $ \s ->
71 case (myThreadId# s) of (# s1, id #) -> (# s1, ThreadId id #)
75 case (yield# s) of s1 -> (# s1, () #)
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 }
95 #if defined(__PARALLEL_HASKELL__) || defined (__GRANSIM__)
96 par x y = case (par# x) of { 0# -> parError; _ -> y }
103 %************************************************************************
105 \subsection[mvars]{M-Structures}
107 %************************************************************************
109 M-Vars are rendezvous points for concurrent threads. They begin
110 empty, and any attempt to read an empty M-Var blocks. When an M-Var
111 is written, a single blocked thread may be freed. Reading an M-Var
112 toggles its state from full back to empty. Therefore, any value
113 written to an M-Var may only be read once. Multiple reads and writes
114 are allowed, but there must be at least one read between any two
118 --Defined in IOBase to avoid cycle: data MVar a = MVar (SynchVar# RealWorld a)
120 instance Eq (MVar a) where
121 (MVar mvar1#) == (MVar mvar2#) = sameMVar# mvar1# mvar2#
123 newEmptyMVar :: IO (MVar a)
125 newEmptyMVar = IO $ \ s# ->
127 (# s2#, svar# #) -> (# s2#, MVar svar# #)
129 takeMVar :: MVar a -> IO a
131 takeMVar (MVar mvar#) = IO $ \ s# -> takeMVar# mvar# s#
133 putMVar :: MVar a -> a -> IO ()
135 putMVar (MVar mvar#) x = IO $ \ s# ->
136 case putMVar# mvar# x s# of
139 newMVar :: a -> IO (MVar a)
142 newEmptyMVar >>= \ mvar ->
143 putMVar mvar value >>
146 readMVar :: MVar a -> IO a
149 takeMVar mvar >>= \ value ->
150 putMVar mvar value >>
153 swapMVar :: MVar a -> a -> IO a
156 takeMVar mvar >>= \ old ->
161 Low-level op. for checking whether an MVar is filled-in or not.
162 Notice that the boolean value returned is just a snapshot of
163 the state of the MVar. By the time you get to react on its result,
164 the MVar may have been filled (or emptied) - so be extremely
165 careful when using this operation.
167 If you can re-work your abstractions to avoid having to
168 depend on isEmptyMVar, then you're encouraged to do so,
169 i.e., consider yourself warned about the imprecision in
170 general of isEmptyMVar :-)
172 isEmptyMVar :: MVar a -> IO Bool
173 isEmptyMVar (MVar mv#) = IO $ \ s# ->
174 case isEmptyMVar# mv# s# of
175 (# s2#, flg #) -> (# s2#, not (flg ==# 0#) #)
179 %************************************************************************
181 \subsection{Thread waiting}
183 %************************************************************************
185 @threadDelay@ delays rescheduling of a thread until the indicated
186 number of microseconds have elapsed. Generally, the microseconds are
187 counted by the context switch timer, which ticks in virtual time;
188 however, when there are no runnable threads, we don't accumulate any
189 virtual time, so we start ticking in real time. (The granularity is
190 the effective resolution of the context switch timer, so it is
191 affected by the RTS -C option.)
193 @threadWaitRead@ delays rescheduling of a thread until input on the
194 specified file descriptor is available for reading (just like select).
195 @threadWaitWrite@ is similar, but for writing on a file descriptor.
199 threadDelay, threadWaitRead, threadWaitWrite :: Int -> IO ()
201 threadDelay (I# x#) = IO $ \ s# ->
205 threadWaitRead (I# x#) = IO $ \ s# ->
206 case waitRead# x# s# of
209 threadWaitWrite (I# x#) = IO $ \ s# ->
210 case waitWrite# x# s# of