-- * Basic concurrency operations
ThreadId,
+#ifdef __GLASGOW_HASKELL__
myThreadId,
+#endif
forkIO,
+#ifdef __GLASGOW_HASKELL__
killThread,
throwTo,
+#endif
-- * Scheduling
module Control.Concurrent.SampleVar,
-- * Merging of streams
+#ifndef __HUGS__
mergeIO, -- :: [a] -> [a] -> IO [a]
nmergeIO, -- :: [[a]] -> IO [a]
+#endif
-- $merge
-- * GHC's implementation of concurrency
#endif
#ifdef __HUGS__
-import IOExts ( unsafeInterleaveIO )
-import ConcBase
+import Hugs.ConcBase
#endif
import Control.Concurrent.MVar
import Control.Concurrent.QSemN
import Control.Concurrent.SampleVar
+#ifdef __HUGS__
+type ThreadId = ()
+#endif
+
{- $conc_intro
The concurrency extension for Haskell is described in the paper
Haskell threads can communicate via 'MVar's, a kind of synchronised
mutable variable (see "Control.Concurrent.MVar"). Several common
concurrency abstractions can be built from 'MVar's, and these are
-provided by the "Concurrent" library. Threads may also communicate
-via exceptions.
+provided by the "Control.Concurrent" library.
+In GHC, threads may also communicate via exceptions.
-}
{- $conc_scheduling
is used on the foreign call (and your compiler \/ operating system
supports it). GHC's I\/O system uses non-blocking I\/O internally to
implement thread-friendly I\/O, so calling standard Haskell I\/O
-functions blocks only the thead making the call.
+functions blocks only the thread making the call.
-}
-- Thread Ids, specifically the instances of Eq and Ord for these things.
-- cmp_thread in the RTS.
#ifdef __GLASGOW_HASKELL__
-foreign import ccall unsafe "cmp_thread" cmp_thread :: Addr# -> Addr# -> Int
+id2TSO :: ThreadId -> ThreadId#
+id2TSO (ThreadId t) = t
+
+foreign import ccall unsafe "cmp_thread" cmp_thread :: ThreadId# -> ThreadId# -> Int
-- Returns -1, 0, 1
cmpThread :: ThreadId -> ThreadId -> Ordering
-cmpThread (ThreadId t1) (ThreadId t2) =
- case cmp_thread (unsafeCoerce# t1) (unsafeCoerce# t2) of
+cmpThread t1 t2 =
+ case cmp_thread (id2TSO t1) (id2TSO t2) of
-1 -> LT
0 -> EQ
_ -> GT -- must be 1
instance Ord ThreadId where
compare = cmpThread
-foreign import ccall unsafe "rts_getThreadId" getThreadId :: Addr# -> Int
+foreign import ccall unsafe "rts_getThreadId" getThreadId :: ThreadId# -> Int
instance Show ThreadId where
- showsPrec d (ThreadId t) =
+ showsPrec d t =
showString "ThreadId " .
- showsPrec d (getThreadId (unsafeCoerce# t))
+ showsPrec d (getThreadId (id2TSO t))
{- |
This sparks off a new thread to run the 'IO' computation passed as the
#endif /* __GLASGOW_HASKELL__ */
-
+#ifndef __HUGS__
max_buff_size :: Int
max_buff_size = 1
return val
where
mapIO f xs = sequence (map f xs)
+#endif /* __HUGS__ */
-- ---------------------------------------------------------------------------
-- More docs
> return mvar
Note that we use 'finally' from the
- "Exception" module to make sure that the
+ "Control.Exception" module to make sure that the
'MVar' is written to even if the thread dies or
is killed for some reason.
The rescheduling timer runs on a 20ms granularity by
default, but this may be altered using the
- @-i<n>@ RTS option. After a rescheduling
+ @-i\<n\>@ RTS option. After a rescheduling
\"tick\" the running thread is pre-empted as soon as
possible.
One final note: the
@aaaa@ @bbbb@ example may not
work too well on GHC (see Scheduling, above), due
- to the locking on a 'Handle'. Only one thread
- may hold the lock on a 'Handle' at any one
+ to the locking on a 'System.IO.Handle'. Only one thread
+ may hold the lock on a 'System.IO.Handle' at any one
time, so if a reschedule happens while a thread is holding the
lock, the other thread won't be able to run. The upshot is that
the switch from @aaaa@ to