X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=Control%2FConcurrent%2FSampleVar.hs;h=ca68a38f76714e7d9d1761411ff68c7e9df4123f;hb=41e8fba828acbae1751628af50849f5352b27873;hp=2b2909257ac578bd87db1516315f847f43e6cd3e;hpb=f7a485978f04e84b086f1974b88887cc72d832d0;p=ghc-base.git diff --git a/Control/Concurrent/SampleVar.hs b/Control/Concurrent/SampleVar.hs index 2b29092..ca68a38 100644 --- a/Control/Concurrent/SampleVar.hs +++ b/Control/Concurrent/SampleVar.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE CPP #-} + ----------------------------------------------------------------------------- -- | -- Module : Control.Concurrent.SampleVar @@ -6,7 +8,7 @@ -- -- Maintainer : libraries@haskell.org -- Stability : experimental --- Portability : non-portable +-- Portability : non-portable (concurrency) -- -- Sample variables -- @@ -14,13 +16,15 @@ module Control.Concurrent.SampleVar ( + -- * Sample Variables SampleVar, -- :: type _ = - newEmptySampleVar, -- :: IO (SampleVar a) + newEmptySampleVar, -- :: IO (SampleVar a) newSampleVar, -- :: a -> IO (SampleVar a) - emptySampleVar, -- :: SampleVar a -> IO () - readSampleVar, -- :: SampleVar a -> IO a - writeSampleVar -- :: SampleVar a -> a -> IO () + emptySampleVar, -- :: SampleVar a -> IO () + readSampleVar, -- :: SampleVar a -> IO a + writeSampleVar, -- :: SampleVar a -> a -> IO () + isEmptySampleVar, -- :: SampleVar a -> IO Bool ) where @@ -28,69 +32,101 @@ import Prelude import Control.Concurrent.MVar --- Sample variables are slightly different from a normal MVar: +import Control.Exception ( mask_ ) + +import Data.Functor ( (<$>) ) + +import Data.Typeable + +#include "Typeable.h" + +-- | +-- Sample variables are slightly different from a normal 'MVar': -- --- * Reading an empty SampleVar causes the reader to block. --- (same as takeMVar on empty MVar) +-- * Reading an empty 'SampleVar' causes the reader to block. +-- (same as 'takeMVar' on empty 'MVar') -- --- * Reading a filled SampleVar empties it and returns value. --- (same as takeMVar) +-- * Reading a filled 'SampleVar' empties it and returns value. +-- (same as 'takeMVar') -- --- * Writing to an empty SampleVar fills it with a value, and --- potentially, wakes up a blocked reader (same as for putMVar on --- empty MVar). +-- * Writing to an empty 'SampleVar' fills it with a value, and +-- potentially, wakes up a blocked reader (same as for 'putMVar' on +-- empty 'MVar'). -- --- * Writing to a filled SampleVar overwrites the current value. --- (different from putMVar on full MVar.) +-- * Writing to a filled 'SampleVar' overwrites the current value. +-- (different from 'putMVar' on full 'MVar'.) -type SampleVar a - = MVar (Int, -- 1 == full - -- 0 == empty - -- <0 no of readers blocked - MVar a) +newtype SampleVar a = SampleVar ( MVar ( Int -- 1 == full + -- 0 == empty + -- <0 no of readers blocked + , MVar a + ) + ) + deriving (Eq) --- Initally, a SampleVar is empty/unfilled. +INSTANCE_TYPEABLE1(SampleVar,sampleVarTc,"SampleVar") +-- |Build a new, empty, 'SampleVar' newEmptySampleVar :: IO (SampleVar a) newEmptySampleVar = do v <- newEmptyMVar - newMVar (0,v) + SampleVar <$> newMVar (0,v) +-- |Build a 'SampleVar' with an initial value. newSampleVar :: a -> IO (SampleVar a) newSampleVar a = do - v <- newEmptyMVar - putMVar v a - newMVar (1,v) + v <- newMVar a + SampleVar <$> newMVar (1,v) +-- |If the SampleVar is full, leave it empty. Otherwise, do nothing. emptySampleVar :: SampleVar a -> IO () -emptySampleVar v = do - (readers, var) <- takeMVar v - if readers >= 0 then +emptySampleVar (SampleVar v) = mask_ $ do + s@(readers, var) <- takeMVar v + if readers > 0 then do + _ <- takeMVar var putMVar v (0,var) else - putMVar v (readers,var) + putMVar v s +-- |Wait for a value to become available, then take it and return. +readSampleVar :: SampleVar a -> IO a +readSampleVar (SampleVar svar) = mask_ $ do -- -- filled => make empty and grab sample -- not filled => try to grab value, empty when read val. -- -readSampleVar :: SampleVar a -> IO a -readSampleVar svar = do (readers,val) <- takeMVar svar - putMVar svar (readers-1,val) + let readers' = readers-1 + readers' `seq` putMVar svar (readers',val) takeMVar val +-- |Write a value into the 'SampleVar', overwriting any previous value that +-- was there. +writeSampleVar :: SampleVar a -> a -> IO () +writeSampleVar (SampleVar svar) v = mask_ $ do -- -- filled => overwrite -- not filled => fill, write val -- -writeSampleVar :: SampleVar a -> a -> IO () -writeSampleVar svar v = do - (readers,val) <- takeMVar svar + s@(readers,val) <- takeMVar svar case readers of - 1 -> - swapMVar val v >> - putMVar svar (1,val) - _ -> - putMVar val v >> - putMVar svar (min 1 (readers+1), val) + 1 -> + swapMVar val v >> + putMVar svar s + _ -> + putMVar val v >> + let readers' = min 1 (readers+1) + in readers' `seq` putMVar svar (readers', val) + +-- | Returns 'True' if the 'SampleVar' is currently empty. +-- +-- Note that this function is only useful if you know that no other +-- threads can be modifying the state of the 'SampleVar', because +-- otherwise the state of the 'SampleVar' may have changed by the time +-- you see the result of 'isEmptySampleVar'. +-- +isEmptySampleVar :: SampleVar a -> IO Bool +isEmptySampleVar (SampleVar svar) = do + (readers, _) <- readMVar svar + return (readers <= 0) +