home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 876 / hugs.sis / ConcBase.hs < prev    next >
Encoding:
Text File  |  2000-09-21  |  4.7 KB  |  165 lines

  1. -----------------------------------------------------------------------------
  2. -- This implements Concurrent Haskell's "MVar"s as described in the paper
  3. --
  4. --   "Concurrent Haskell"
  5. --   Simon Peyton Jones, Andrew Gordon and Sigbjorn Finne.
  6. --   In Proceedings of the ACM Symposium on Principles of Programming
  7. --   Languages,St Petersburg Beach, Florida, January 1996. 
  8. --   http://www.dcs.gla.ac.uk/fp/authors/Simon_Peyton_Jones/
  9. --     concurrent-haskell.ps
  10. --
  11. -- except that we have made the following name changes for compatability
  12. -- with GHC 2.05.
  13. --
  14. --   newMVar  -> newEmptyMVar
  15. --
  16. -- There is one significant difference between this implementation and
  17. -- GHC 2.05: 
  18. --
  19. -- o GHC uses preemptive multitasking.
  20. -- 
  21. --   Context switches can occur at any time (except if you call a C
  22. --   function (like "getchar") which blocks the entire process while
  23. --   waiting for input.
  24. -- 
  25. -- o Hugs uses cooperative multitasking.  
  26. -- 
  27. --   Context switches only occur when you use one of the primitives
  28. --   defined in this module.  This means that programs such as:
  29. -- 
  30. --     main = forkIO (write 'a') >> write 'b'
  31. --     where
  32. --      write c = putChar c >> write c
  33. -- 
  34. --   will print either "aaaaaaaaaaaaaa..." or "bbbbbbbbbbbb..."
  35. --   instead of some random interleaving of 'a's and 'b's.
  36. -- 
  37. -- Cooperative multitasking is sufficient for writing coroutines and simple
  38. -- graphical user interfaces but the usual assumptions of fairness don't
  39. -- apply and Channel.getChanContents cannot be implemented.
  40. -----------------------------------------------------------------------------
  41. module ConcBase(
  42.     forkIO,
  43.     runOrBlockIO,
  44.     MVar,
  45.     newEmptyMVar, newMVar, takeMVar, putMVar,
  46.     swapMVar, readMVar, isEmptyMVar,
  47.         yield
  48.     ) where
  49.  
  50. import IO(IOMode, Handle, ioeGetErrorString) -- for binary file ops
  51. import IOExts
  52.  
  53. ----------------------------------------------------------------
  54. -- The interface
  55. ----------------------------------------------------------------
  56.  
  57. forkIO      :: IO () -> IO () -- Spawn a thread
  58.  
  59. newEmptyMVar :: IO (MVar a)
  60. newMVar      :: a -> IO (MVar a)
  61. takeMVar     :: MVar a -> IO a
  62. putMVar      :: MVar a -> a -> IO ()
  63.  
  64. instance Eq (MVar a) where
  65.   (==) = primEqMVar
  66.  
  67. -- Spawn a thread and wait for it to return or block
  68. runOrBlockIO :: IO a -> IO (IOResult a)
  69.  
  70. swapMVar :: MVar a -> a -> IO a
  71.  
  72. readMVar :: MVar a -> IO a
  73.  
  74. isEmptyMVar :: MVar a -> IO Bool
  75.  
  76. ----------------------------------------------------------------
  77. -- Easy implementations (definable using the primitive operations)
  78. ----------------------------------------------------------------
  79.  
  80. swapMVar var new = do
  81.   old <- takeMVar var
  82.   putMVar var new
  83.   return old
  84.  
  85. readMVar mvar =
  86.     takeMVar mvar    >>= \ value ->
  87.     putMVar mvar value    >>
  88.     return value
  89.  
  90. ----------------------------------------------------------------
  91. -- Implementation
  92. ----------------------------------------------------------------
  93.  
  94. suspend :: IO a
  95. suspend = IO (\f s -> Hugs_SuspendThread)
  96.  
  97. yield   :: IO ()
  98. yield    = suspend
  99.  
  100. -- The thread is scheduled immediately and runs with its own success/error
  101. -- continuations.
  102. runOrBlockIO (IO m) = IO (\f s -> s $! (m Hugs_Error Hugs_Return))  
  103.  
  104. -- suspend current thread passing its continuation to m
  105. blockIO :: ((a -> IOResult a) -> IO a) -> IO a
  106. blockIO m = IO (\ f s -> 
  107.   case m s of { IO ms -> ms f (const Hugs_SuspendThread) }
  108.   )
  109.  
  110. -- continue the continuation, then go on
  111. continueIO :: IOResult a -> IO ()
  112. continueIO cc = IO (\ f s -> cc `seq` s ())
  113.  
  114. -- The thread is scheduled immediately and runs with its own success/error
  115. -- continuations.
  116. forkIO m = runOrBlockIO (m `catch` forkErrHandler) >> return ()
  117.  
  118. forkErrHandler :: IOError -> IO a
  119. forkErrHandler e = do
  120.     putStr "Uncaught error in forked process: \n  "
  121.     putStr (ioeGetErrorString e)
  122.     putStr "\n"           
  123.     suspend
  124.  
  125. newtype MVar a = MkMVar (IORef (Either a [a -> IOResult a]))
  126.  
  127. newEmptyMVar = fmap MkMVar (newIORef (Right []))
  128.  
  129. newMVar x    = fmap MkMVar (newIORef (Left x))
  130.  
  131. takeMVar (MkMVar v) =
  132.   readIORef v >>= \ state ->
  133.   case state of
  134.   Left a ->
  135.     writeIORef v (Right []) >>
  136.     return a
  137.   Right cs ->
  138.     blockIO (\cc ->
  139.       writeIORef v (Right (cc:cs)) >>
  140.       suspend
  141.     )
  142.  
  143. putMVar (MkMVar v) a =
  144.   readIORef v >>= \ state ->
  145.   case state of
  146.   Left a ->
  147.     error "putMVar {full MVar}"
  148.   Right [] ->
  149.     writeIORef v (Left a)   >>
  150.     return ()
  151.   Right (c:cs) ->
  152.     writeIORef v (Right cs) >>
  153.     continueIO (c a)       >> -- schedule the blocked process
  154.     return ()                 -- continue with this process
  155.  
  156. primEqMVar   :: MVar a -> MVar a -> Bool
  157. MkMVar v1 `primEqMVar` MkMVar v2 = v1 == v2
  158.  
  159. isEmptyMVar (MkMVar v) =
  160.   readIORef v >>= \state -> case state of
  161.                               Left a  -> return False
  162.                               Right a -> return True
  163.  
  164. -----------------------------------------------------------------------------
  165.