{- | Module : Description : This module implements a buffer with cells and futures. Maintainer : mwillig@gmx.de Stability : experimental Portability : non-portable (requires Futures) This module implements one-place buffers using futures. Warning: All operations on buffers should only be used within the global wrapper function 'Futures.withFuturesDo'! -} module Control.Concurrent.Futures.Buffer ( Buffer, -- Cell, -- cell, -- testAndSet, wait, newBuf, putBuf, getBuf ) where import Control.Concurrent.Futures.Futures as Futures import Control.Concurrent.MVar import System.IO -- -- The buffer type contains of 3 cells and a handle. type Buffer a = (Cell Bool, Cell Bool, Cell a, Cell (Bool -> IO ())) ----------------------------------------------------------------------- ---Cells -- | A cell type. Cells provide an automic 'exchange' operation. type Cell a = MVar a -- | Creates a new cell. cell :: a -> IO (Cell a) cell a = newMVar a exchange :: Cell a -> a -> IO a exchange a b = swapMVar a b -- | TestAndSet on cells provides test and set functions in one atomic operation. testAndSet :: Cell Bool -> IO t -> IO Bool testAndSet cell code = do val <- (exchange cell True) case val of True -> return True False -> do code exchange cell False -- | A test on cells --tsExample = do -- c <- Buffer.cell False -- code <- (\x -> do putStrLn "The code." return x) -- Buffer.testAndSet c code -- return c ------------------------------------------------------------------------------- -- | Waits its argument to become true wait :: Bool -> IO Bool wait x = do case x of True -> return x otherwise -> return x -- | Creates a new empty buffer. newBuf :: IO (Buffer a) newBuf = do (h,f) <- Futures.newhandled (h',f') <- Futures.newhandled putg <- cell True getg <- cell f stored <- cell f' handler <- cell h return (putg,getg,stored,handler) -- | Puts a new value to a buffer. 'putBuf' blocks if -- the buffer is full. putBuf :: Buffer a -> a -> IO () putBuf (putg,getg,stored,handler) val = do (h,f) <- Futures.newhandled old_value <- exchange putg f wait old_value exchange stored val old_handler <- exchange handler h old_handler True -- | Gets the contents of a non-empty buffer. If the buffer is empty, then -- this function blocks until the buffer is filled. getBuf :: Buffer a -> IO a getBuf (putg,getg,stored,handler) = do (h,f) <- Futures.newhandled (h',f') <- Futures.newhandled old_value <- exchange getg f wait old_value val <- exchange stored f' old_handler <- exchange handler h old_handler True return val