{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
module Control.Concurrent.Chan
(
Chan,
newChan,
writeChan,
readChan,
dupChan,
unGetChan,
isEmptyChan,
getChanContents,
writeList2Chan,
) where
import Prelude
import System.IO.Unsafe ( unsafeInterleaveIO )
import Control.Concurrent.MVar
import Control.Exception (mask_)
import Data.Typeable
#define _UPK_(x) {-# UNPACK #-} !(x)
data Chan a
= Chan _UPK_(MVar (Stream a))
_UPK_(MVar (Stream a))
deriving (Eq,Typeable)
type Stream a = MVar (ChItem a)
data ChItem a = ChItem a _UPK_(Stream a)
newChan :: IO (Chan a)
newChan = do
hole <- newEmptyMVar
readVar <- newMVar hole
writeVar <- newMVar hole
return (Chan readVar writeVar)
writeChan :: Chan a -> a -> IO ()
writeChan (Chan _ writeVar) val = do
new_hole <- newEmptyMVar
mask_ $ do
old_hole <- takeMVar writeVar
putMVar old_hole (ChItem val new_hole)
putMVar writeVar new_hole
readChan :: Chan a -> IO a
readChan (Chan readVar _) = do
modifyMVarMasked readVar $ \read_end -> do
(ChItem val new_read_end) <- readMVar read_end
return (new_read_end, val)
dupChan :: Chan a -> IO (Chan a)
dupChan (Chan _ writeVar) = do
hole <- readMVar writeVar
newReadVar <- newMVar hole
return (Chan newReadVar writeVar)
unGetChan :: Chan a -> a -> IO ()
unGetChan (Chan readVar _) val = do
new_read_end <- newEmptyMVar
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://ghc.haskell.org/trac/ghc/ticket/4154> for details" #-}
isEmptyChan :: Chan a -> IO Bool
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://ghc.haskell.org/trac/ghc/ticket/4154> for details" #-}
getChanContents :: Chan a -> IO [a]
getChanContents ch
= unsafeInterleaveIO (do
x <- readChan ch
xs <- getChanContents ch
return (x:xs)
)
writeList2Chan :: Chan a -> [a] -> IO ()
writeList2Chan ch ls = sequence_ (map (writeChan ch) ls)