[project @ 2000-04-10 16:02:58 by simonpj]
[ghc-hetmet.git] / ghc / lib / std / PrelConc.lhs
index e2da14b..f096db1 100644 (file)
@@ -7,68 +7,94 @@
 Basic concurrency stuff
 
 \begin{code}
-{-# OPTIONS -fno-implicit-prelude #-}
-module PrelConc(
-               -- Forking and suchlike
-       ST,     forkST,
-       IO,     forkIO, 
-       par, fork,
-       threadDelay, threadWaitRead, threadWaitWrite,
-
-               -- MVars
-       MVar, newMVar, newEmptyMVar, takeMVar, putMVar, readMVar, swapMVar
+{-# OPTIONS -fcompiling-prelude -fno-implicit-prelude #-}
+
+module PrelConc
+       ( ThreadId(..)
+
+       -- Forking and suchlike
+       , myThreadId    -- :: IO ThreadId
+       , killThread    -- :: ThreadId -> IO ()
+       , raiseInThread -- :: ThreadId -> Exception -> IO ()
+       , par           -- :: a -> b -> b
+       , seq           -- :: a -> b -> b
+       , yield         -- :: IO ()
+
+       -- Waiting
+       , threadDelay           -- :: Int -> IO ()
+       , threadWaitRead        -- :: Int -> IO ()
+       , threadWaitWrite       -- :: Int -> IO ()
+
+       -- MVars
+       , MVar          -- abstract
+       , newMVar       -- :: a -> IO (MVar a)
+       , newEmptyMVar  -- :: IO (MVar a)
+       , takeMVar      -- :: MVar a -> IO a
+       , putMVar       -- :: MVar a -> a -> IO ()
+       , readMVar      -- :: MVar a -> IO a
+       , swapMVar      -- :: MVar a -> a -> IO a
+       , isEmptyMVar   -- :: MVar a -> IO Bool
+
     ) where
 
 import PrelBase
-import PrelST          ( ST(..), STret(..), StateAndPtr#(..) )
-import PrelIOBase      ( IO(..), IOResult(..), MVar(..) )
-import PrelErr         ( parError )
+import PrelErr ( parError, seqError )
+import PrelST          ( liftST )
+import PrelIOBase      ( IO(..), MVar(..), unsafePerformIO )
 import PrelBase                ( Int(..) )
-import PrelGHC         ( fork#, delay#, waitRead#, waitWrite#,
-                         SynchVar#, newSynchVar#, takeMVar#, putMVar#,
-                         State#, RealWorld, par#
-                       )
+import PrelException    ( Exception(..), AsyncException(..) )
 
-infixr 0 `par`, `fork`
+infixr 0 `par`, `seq`
 \end{code}
 
-
-
 %************************************************************************
 %*                                                                     *
-\subsection{@par@, and @fork@}
+\subsection{@ThreadId@, @par@, and @fork@}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-forkST :: ST s a -> ST s a
-
-forkST (ST action) = ST $ \ s -> 
-       let d@(STret _ r) = action s in
-       d `fork` STret s r
-
-forkIO :: IO () -> IO ()
-forkIO (IO action) = IO $ \ s -> (action s) `fork` IOok s ()
-
-par, fork :: Eval a => a -> b -> b
+data ThreadId = ThreadId ThreadId#
+-- ToDo: data ThreadId = ThreadId (Weak ThreadId#)
+-- But since ThreadId# is unlifted, the Weak type must use open
+-- type variables.
+
+--forkIO has now been hoisted out into the Concurrent library.
+
+killThread :: ThreadId -> IO ()
+killThread (ThreadId id) = IO $ \ s ->
+   case (killThread# id (AsyncException ThreadKilled) s) of s1 -> (# s1, () #)
+
+raiseInThread :: ThreadId -> Exception -> IO ()
+raiseInThread (ThreadId id) ex = IO $ \ s ->
+   case (killThread# id ex s) of s1 -> (# s1, () #)
+
+myThreadId :: IO ThreadId
+myThreadId = IO $ \s ->
+   case (myThreadId# s) of (# s1, id #) -> (# s1, ThreadId id #)
+
+yield :: IO ()
+yield = IO $ \s -> 
+   case (yield# s) of s1 -> (# s1, () #)
+
+-- "seq" is defined a bit wierdly (see below)
+--
+-- The reason for the strange "0# -> parError" case is that
+-- it fools the compiler into thinking that seq is non-strict in
+-- its second argument (even if it inlines seq at the call site).
+-- If it thinks seq is strict in "y", then it often evaluates
+-- "y" before "x", which is totally wrong.  
+--
+-- Just before converting from Core to STG there's a bit of magic
+-- that recognises the seq# and eliminates the duff case.
+
+{-# INLINE seq  #-}
+seq :: a -> b -> b
+seq  x y = case (seq#  x) of { 0# -> seqError; _ -> y }
 
 {-# INLINE par  #-}
-{-# INLINE fork #-}
-
-#if defined(__PARALLEL_HASKELL__) || defined (__GRANSIM__)
-par  x y = case (par#  x) of { 0# -> parError; _ -> y }
-#else
-par  x y = y
-#endif
-
-#if defined(__CONCURRENT_HASKELL__) || defined (__GRANSIM__)
-fork x y = case (fork# x) of { 0# -> parError; _ -> y }
-#else
-fork x y = y
-#endif
-
-runOrBlockIO m = m                     -- ?????
-
+par :: a -> b -> b
+par  x y = case (par# x) of { 0# -> parError; _ -> y }
 \end{code}
 
 %************************************************************************
@@ -88,26 +114,21 @@ writes.
 \begin{code}
 --Defined in IOBase to avoid cycle: data MVar a = MVar (SynchVar# RealWorld a)
 
-instance Eq (MVar a) where
-       (MVar mvar1#) == (MVar mvar2#) = sameMVar# mvar1# mvar2#
-
 newEmptyMVar  :: IO (MVar a)
 
 newEmptyMVar = IO $ \ s# ->
-    case newSynchVar# s# of
-        StateAndSynchVar# s2# svar# -> IOok s2# (MVar svar#)
+    case newMVar# s# of
+         (# s2#, svar# #) -> (# s2#, MVar svar# #)
 
 takeMVar :: MVar a -> IO a
 
-takeMVar (MVar mvar#) = IO $ \ s# ->
-    case takeMVar# mvar# s# of
-        StateAndPtr# s2# r -> IOok s2# r
+takeMVar (MVar mvar#) = IO $ \ s# -> takeMVar# mvar# s#
 
 putMVar  :: MVar a -> a -> IO ()
 
 putMVar (MVar mvar#) x = IO $ \ s# ->
     case putMVar# mvar# x s# of
-        s2# -> IOok s2# ()
+        s2# -> (# s2#, () #)
 
 newMVar :: a -> IO (MVar a)
 
@@ -129,6 +150,23 @@ swapMVar mvar new =
     takeMVar mvar      >>= \ old ->
     putMVar mvar new   >>
     return old
+
+{- 
+ Low-level op. for checking whether an MVar is filled-in or not.
+ Notice that the boolean value returned  is just a snapshot of
+ the state of the MVar. By the time you get to react on its result,
+ the MVar may have been filled (or emptied) - so be extremely
+ careful when using this operation.
+
+ If you can re-work your abstractions to avoid having to
+ depend on isEmptyMVar, then you're encouraged to do so,
+ i.e., consider yourself warned about the imprecision in
+ general of isEmptyMVar :-)
+-}
+isEmptyMVar :: MVar a -> IO Bool
+isEmptyMVar (MVar mv#) = IO $ \ s# -> 
+    case isEmptyMVar# mv# s# of
+        (# s2#, flg #) -> (# s2#, not (flg ==# 0#) #)
 \end{code}
 
 
@@ -153,25 +191,7 @@ specified file descriptor is available for reading (just like select).
 \begin{code}
 threadDelay, threadWaitRead, threadWaitWrite :: Int -> IO ()
 
-threadDelay (I# x#) = IO $ \ s# ->
-    case delay# x# s# of
-      s2# -> IOok s2# ()
-
-threadWaitRead (I# x#) = IO $ \ s# -> 
-    case waitRead# x# s# of
-      s2# -> IOok s2# ()
-
-threadWaitWrite (I# x#) = IO $ \ s# ->
-    case waitWrite# x# s# of
-      s2# -> IOok s2# ()
-\end{code}
-
-%*********************************************************
-%*                                                     *
-\subsection{Ghastly return types}
-%*                                                     *
-%*********************************************************
-
-\begin{code}
-data StateAndSynchVar# s elt = StateAndSynchVar# (State# s) (SynchVar# s elt)
+threadDelay     (I# ms) = IO $ \s -> case delay# ms s     of s -> (# s, () #)
+threadWaitRead  (I# fd) = IO $ \s -> case waitRead# fd s  of s -> (# s, () #)
+threadWaitWrite (I# fd) = IO $ \s -> case waitWrite# fd s of s -> (# s, () #)
 \end{code}