+{-# LANGUAGE CPP #-}
+
-----------------------------------------------------------------------------
-- |
-- Module : Control.Concurrent.Chan
--
-- Maintainer : libraries@haskell.org
-- Stability : experimental
--- Portability : non-portable (concurrency).
+-- Portability : non-portable (concurrency)
--
-- Unbounded channels.
--
module Control.Concurrent.Chan
(
- -- * The 'Chan' type
- Chan, -- abstract
-
- -- * Operations
- newChan, -- :: IO (Chan a)
- writeChan, -- :: Chan a -> a -> IO ()
- readChan, -- :: Chan a -> IO a
- dupChan, -- :: Chan a -> IO (Chan a)
- unGetChan, -- :: Chan a -> a -> IO ()
- isEmptyChan, -- :: Chan a -> IO Bool
-
- -- * Stream interface
- getChanContents, -- :: Chan a -> IO [a]
- writeList2Chan, -- :: Chan a -> [a] -> IO ()
+ -- * The 'Chan' type
+ Chan, -- abstract
+
+ -- * Operations
+ newChan, -- :: IO (Chan a)
+ writeChan, -- :: Chan a -> a -> IO ()
+ readChan, -- :: Chan a -> IO a
+ dupChan, -- :: Chan a -> IO (Chan a)
+ unGetChan, -- :: Chan a -> a -> IO ()
+ isEmptyChan, -- :: Chan a -> IO Bool
+
+ -- * Stream interface
+ getChanContents, -- :: Chan a -> IO [a]
+ writeList2Chan, -- :: Chan a -> [a] -> IO ()
) where
import Prelude
-import System.IO.Unsafe ( unsafeInterleaveIO )
+import System.IO.Unsafe ( unsafeInterleaveIO )
import Control.Concurrent.MVar
import Data.Typeable
data Chan a
= Chan (MVar (Stream a))
(MVar (Stream a))
+ deriving Eq
INSTANCE_TYPEABLE1(Chan,chanTc,"Chan")
newChan :: IO (Chan a)
newChan = do
hole <- newEmptyMVar
- read <- newMVar hole
- write <- newMVar hole
- return (Chan read write)
+ readVar <- newMVar hole
+ writeVar <- newMVar hole
+ return (Chan readVar writeVar)
-- To put an element on a channel, a new hole at the write end is created.
-- What was previously the empty @MVar@ at the back of the channel is then
-- |Write a value to a 'Chan'.
writeChan :: Chan a -> a -> IO ()
-writeChan (Chan _read write) val = do
+writeChan (Chan _ writeVar) val = do
new_hole <- newEmptyMVar
- modifyMVar_ write $ \old_hole -> do
+ modifyMVar_ writeVar $ \old_hole -> do
putMVar old_hole (ChItem val new_hole)
return new_hole
-- |Read the next value from the 'Chan'.
readChan :: Chan a -> IO a
-readChan (Chan read _write) = do
- modifyMVar read $ \read_end -> do
+readChan (Chan readVar _) = do
+ modifyMVar readVar $ \read_end -> do
(ChItem val new_read_end) <- readMVar read_end
- -- Use readMVar here, not takeMVar,
- -- else dupChan doesn't work
+ -- Use readMVar here, not takeMVar,
+ -- else dupChan doesn't work
return (new_read_end, val)
-- |Duplicate a 'Chan': the duplicate channel begins empty, but data written to
-- either channel from then on will be available from both. Hence this creates
-- a kind of broadcast channel, where data written by anyone is seen by
-- everyone else.
+--
+-- (Note that a duplicated channel is not equal to its original.
+-- So: @fmap (c /=) $ dupChan c@ returns @True@ for all @c@.)
dupChan :: Chan a -> IO (Chan a)
-dupChan (Chan _read write) = do
- hole <- readMVar write
- new_read <- newMVar hole
- return (Chan new_read write)
+dupChan (Chan _ writeVar) = do
+ hole <- readMVar writeVar
+ newReadVar <- newMVar hole
+ return (Chan newReadVar writeVar)
-- |Put a data item back onto a channel, where it will be the next item read.
unGetChan :: Chan a -> a -> IO ()
-unGetChan (Chan read _write) val = do
+unGetChan (Chan readVar _) val = do
new_read_end <- newEmptyMVar
- modifyMVar_ read $ \read_end -> do
+ modifyMVar_ readVar $ \read_end -> do
putMVar new_read_end (ChItem val read_end)
return new_read_end
+{-# DEPRECATED unGetChan "if you need this operation, use Control.Concurrent.STM.TChan instead. See http://hackage.haskell.org/trac/ghc/ticket/4154 for details" #-}
-- |Returns 'True' if the supplied 'Chan' is empty.
isEmptyChan :: Chan a -> IO Bool
-isEmptyChan (Chan read write) = do
- withMVar read $ \r -> do
- w <- readMVar write
+isEmptyChan (Chan readVar writeVar) = do
+ withMVar readVar $ \r -> do
+ w <- readMVar writeVar
let eq = r == w
eq `seq` return eq
+{-# DEPRECATED isEmptyChan "if you need this operation, use Control.Concurrent.STM.TChan instead. See http://hackage.haskell.org/trac/ghc/ticket/4154 for details" #-}
-- Operators for interfacing with functional streams.
getChanContents :: Chan a -> IO [a]
getChanContents ch
= unsafeInterleaveIO (do
- x <- readChan ch
- xs <- getChanContents ch
- return (x:xs)
+ x <- readChan ch
+ xs <- getChanContents ch
+ return (x:xs)
)
-- |Write an entire list of items to a 'Chan'.