module Control.Concurrent.BoundedChan(
BoundedChan
, newBoundedChan
, writeChan
, readChan
, isEmptyChan
, getChanContents
, writeList2Chan
)
where
import Control.Concurrent.MVar (MVar, isEmptyMVar, newEmptyMVar, newMVar,
putMVar, takeMVar)
import Control.Monad (replicateM)
import Data.Array (Array, (!), listArray)
import System.IO.Unsafe (unsafeInterleaveIO)
data BoundedChan a = BC {
_size :: Int
, _contents :: Array Int (MVar a)
, _writePos :: MVar Int
, _readPos :: MVar Int
}
newBoundedChan :: Int -> IO (BoundedChan a)
newBoundedChan x = do
entls <- replicateM x newEmptyMVar
wpos <- newMVar 0
rpos <- newMVar 0
let entries = listArray (0, x 1) entls
return (BC x entries wpos rpos)
writeChan :: BoundedChan a -> a -> IO ()
writeChan (BC size contents wposMV _) x = do
wpos <- takeMVar wposMV
putMVar wposMV $! (wpos + 1) `mod` size
putMVar (contents ! wpos) x
readChan :: BoundedChan a -> IO a
readChan (BC size contents _ rposMV) = do
rpos <- takeMVar rposMV
putMVar rposMV $! (rpos + 1) `mod` size
takeMVar (contents ! rpos)
isEmptyChan :: BoundedChan a -> IO Bool
isEmptyChan (BC _ contents _ rposMV) = do
rpos <- takeMVar rposMV
res <- isEmptyMVar (contents ! rpos)
putMVar rposMV rpos
return res
getChanContents :: BoundedChan a -> IO [a]
getChanContents ch = unsafeInterleaveIO $ do
x <- readChan ch
xs <- getChanContents ch
return (x:xs)
writeList2Chan :: BoundedChan a -> [a] -> IO ()
writeList2Chan = mapM_ . writeChan