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 -- $Id: Concurrent.hs,v 1.1 2001/06/28 14:15:01 simonmar Exp $
13 -- A common interface to a collection of useful concurrency
16 -----------------------------------------------------------------------------
18 module Control.Concurrent
19 ( module Control.Concurrent.Chan
20 , module Control.Concurrent.CVar
21 , module Control.Concurrent.MVar
22 , module Control.Concurrent.QSem
23 , module Control.Concurrent.QSemN
24 , module Control.Concurrent.SampleVar
27 , forkIO -- :: IO () -> IO ()
28 #elif defined(__GLASGOW_HASKELL__)
31 -- Forking and suchlike
32 , myThreadId -- :: IO ThreadId
33 , killThread -- :: ThreadId -> IO ()
34 , throwTo -- :: ThreadId -> Exception -> IO ()
36 , par -- :: a -> b -> b
37 , seq -- :: a -> b -> b
38 #ifdef __GLASGOW_HASKELL__
39 , fork -- :: a -> b -> b
43 #ifdef __GLASGOW_HASKELL__
44 , threadDelay -- :: Int -> IO ()
45 , threadWaitRead -- :: Int -> IO ()
46 , threadWaitWrite -- :: Int -> IO ()
50 , mergeIO -- :: [a] -> [a] -> IO [a]
51 , nmergeIO -- :: [[a]] -> IO [a]
56 import Control.Exception as Exception
58 #ifdef __GLASGOW_HASKELL__
60 import GHC.TopHandler ( reportStackOverflow, reportError )
61 import GHC.IOBase ( IO(..) )
62 import GHC.IOBase ( unsafePerformIO , unsafeInterleaveIO )
63 import GHC.Base ( fork# )
64 import GHC.Prim ( Addr#, unsafeCoerce# )
68 import IOExts ( unsafeInterleaveIO, unsafePerformIO )
72 import Control.Concurrent.MVar
73 import Control.Concurrent.CVar
74 import Control.Concurrent.Chan
75 import Control.Concurrent.QSem
76 import Control.Concurrent.QSemN
77 import Control.Concurrent.SampleVar
79 #ifdef __GLASGOW_HASKELL__
83 -- Thread Ids, specifically the instances of Eq and Ord for these things.
84 -- The ThreadId type itself is defined in std/PrelConc.lhs.
86 -- Rather than define a new primitve, we use a little helper function
87 -- cmp_thread in the RTS.
89 #ifdef __GLASGOW_HASKELL__
90 foreign import ccall "cmp_thread" unsafe cmp_thread :: Addr# -> Addr# -> Int
93 cmpThread :: ThreadId -> ThreadId -> Ordering
94 cmpThread (ThreadId t1) (ThreadId t2) =
95 case cmp_thread (unsafeCoerce# t1) (unsafeCoerce# t2) of
100 instance Eq ThreadId where
102 case t1 `cmpThread` t2 of
106 instance Ord ThreadId where
109 forkIO :: IO () -> IO ThreadId
110 forkIO action = IO $ \ s ->
111 case (fork# action_plus s) of (# s1, id #) -> (# s1, ThreadId id #)
113 action_plus = Exception.catch action childHandler
115 childHandler :: Exception -> IO ()
116 childHandler err = Exception.catch (real_handler err) childHandler
118 real_handler :: Exception -> IO ()
121 -- ignore thread GC and killThread exceptions:
122 BlockedOnDeadMVar -> return ()
123 AsyncException ThreadKilled -> return ()
125 -- report all others:
126 AsyncException StackOverflow -> reportStackOverflow False
127 ErrorCall s -> reportError False s
128 other -> reportError False (showsPrec 0 other "\n")
132 fork x y = unsafePerformIO (forkIO (x `seq` return ())) `seq` y
134 #endif /* __GLASGOW_HASKELL__ */
140 mergeIO :: [a] -> [a] -> IO [a]
141 nmergeIO :: [[a]] -> IO [a]
144 = newEmptyMVar >>= \ tail_node ->
145 newMVar tail_node >>= \ tail_list ->
146 newQSem max_buff_size >>= \ e ->
147 newMVar 2 >>= \ branches_running ->
151 forkIO (suckIO branches_running buff ls) >>
152 forkIO (suckIO branches_running buff rs) >>
153 takeMVar tail_node >>= \ val ->
158 = (MVar (MVar [a]), QSem)
160 suckIO :: MVar Int -> Buffer a -> [a] -> IO ()
162 suckIO branches_running buff@(tail_list,e) vs
164 [] -> takeMVar branches_running >>= \ val ->
166 takeMVar tail_list >>= \ node ->
168 putMVar tail_list node
170 putMVar branches_running (val-1)
173 takeMVar tail_list >>= \ node ->
174 newEmptyMVar >>= \ next_node ->
176 takeMVar next_node >>= \ y ->
178 return y) >>= \ next_node_val ->
179 putMVar node (x:next_node_val) >>
180 putMVar tail_list next_node >>
181 suckIO branches_running buff xs
187 newEmptyMVar >>= \ tail_node ->
188 newMVar tail_node >>= \ tail_list ->
189 newQSem max_buff_size >>= \ e ->
190 newMVar len >>= \ branches_running ->
194 mapIO (\ x -> forkIO (suckIO branches_running buff x)) lss >>
195 takeMVar tail_node >>= \ val ->
199 mapIO f xs = sequence (map f xs)