1 -----------------------------------------------------------------------------
3 -- Module : Control.Concurrent
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/core/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- A common interface to a collection of useful concurrency
14 -----------------------------------------------------------------------------
16 module Control.Concurrent (
17 module Control.Concurrent.Chan,
18 module Control.Concurrent.CVar,
19 module Control.Concurrent.MVar,
20 module Control.Concurrent.QSem,
21 module Control.Concurrent.QSemN,
22 module Control.Concurrent.SampleVar,
24 forkIO, -- :: IO () -> IO ()
27 #ifdef __GLASGOW_HASKELL__
30 -- Forking and suchlike
31 myThreadId, -- :: IO ThreadId
32 killThread, -- :: ThreadId -> IO ()
33 throwTo, -- :: ThreadId -> Exception -> IO ()
35 threadDelay, -- :: Int -> IO ()
36 threadWaitRead, -- :: Int -> IO ()
37 threadWaitWrite, -- :: Int -> IO ()
41 mergeIO, -- :: [a] -> [a] -> IO [a]
42 nmergeIO -- :: [[a]] -> IO [a]
47 import Control.Exception as Exception
49 #ifdef __GLASGOW_HASKELL__
51 import GHC.TopHandler ( reportStackOverflow, reportError )
52 import GHC.IOBase ( IO(..) )
53 import GHC.IOBase ( unsafeInterleaveIO )
58 import IOExts ( unsafeInterleaveIO )
62 import Control.Concurrent.MVar
63 import Control.Concurrent.CVar
64 import Control.Concurrent.Chan
65 import Control.Concurrent.QSem
66 import Control.Concurrent.QSemN
67 import Control.Concurrent.SampleVar
69 -- Thread Ids, specifically the instances of Eq and Ord for these things.
70 -- The ThreadId type itself is defined in std/PrelConc.lhs.
72 -- Rather than define a new primitve, we use a little helper function
73 -- cmp_thread in the RTS.
75 #ifdef __GLASGOW_HASKELL__
76 foreign import ccall unsafe "cmp_thread" cmp_thread :: Addr# -> Addr# -> Int
79 cmpThread :: ThreadId -> ThreadId -> Ordering
80 cmpThread (ThreadId t1) (ThreadId t2) =
81 case cmp_thread (unsafeCoerce# t1) (unsafeCoerce# t2) of
86 instance Eq ThreadId where
88 case t1 `cmpThread` t2 of
92 instance Ord ThreadId where
95 foreign import ccall unsafe "rts_getThreadId" getThreadId :: Addr# -> Int
97 instance Show ThreadId where
98 showsPrec d (ThreadId t) =
99 showString "ThreadId " .
100 showsPrec d (getThreadId (unsafeCoerce# t))
102 forkIO :: IO () -> IO ThreadId
103 forkIO action = IO $ \ s ->
104 case (fork# action_plus s) of (# s1, id #) -> (# s1, ThreadId id #)
106 action_plus = Exception.catch action childHandler
108 childHandler :: Exception -> IO ()
109 childHandler err = Exception.catch (real_handler err) childHandler
111 real_handler :: Exception -> IO ()
114 -- ignore thread GC and killThread exceptions:
115 BlockedOnDeadMVar -> return ()
116 AsyncException ThreadKilled -> return ()
118 -- report all others:
119 AsyncException StackOverflow -> reportStackOverflow False
120 ErrorCall s -> reportError False s
121 other -> reportError False (showsPrec 0 other "\n")
123 #endif /* __GLASGOW_HASKELL__ */
129 mergeIO :: [a] -> [a] -> IO [a]
130 nmergeIO :: [[a]] -> IO [a]
133 = newEmptyMVar >>= \ tail_node ->
134 newMVar tail_node >>= \ tail_list ->
135 newQSem max_buff_size >>= \ e ->
136 newMVar 2 >>= \ branches_running ->
140 forkIO (suckIO branches_running buff ls) >>
141 forkIO (suckIO branches_running buff rs) >>
142 takeMVar tail_node >>= \ val ->
147 = (MVar (MVar [a]), QSem)
149 suckIO :: MVar Int -> Buffer a -> [a] -> IO ()
151 suckIO branches_running buff@(tail_list,e) vs
153 [] -> takeMVar branches_running >>= \ val ->
155 takeMVar tail_list >>= \ node ->
157 putMVar tail_list node
159 putMVar branches_running (val-1)
162 takeMVar tail_list >>= \ node ->
163 newEmptyMVar >>= \ next_node ->
165 takeMVar next_node >>= \ y ->
167 return y) >>= \ next_node_val ->
168 putMVar node (x:next_node_val) >>
169 putMVar tail_list next_node >>
170 suckIO branches_running buff xs
176 newEmptyMVar >>= \ tail_node ->
177 newMVar tail_node >>= \ tail_list ->
178 newQSem max_buff_size >>= \ e ->
179 newMVar len >>= \ branches_running ->
183 mapIO (\ x -> forkIO (suckIO branches_running buff x)) lss >>
184 takeMVar tail_node >>= \ val ->
188 mapIO f xs = sequence (map f xs)