------------------------------------------------------------------------------- |-- Module : Control.Concurrent.SampleVar-- Copyright : (c) The University of Glasgow 2001-- License : BSD-style (see the file libraries/base/LICENSE)-- -- Maintainer : libraries@haskell.org-- Stability : experimental-- Portability : non-portable (concurrency)---- Sample variables-------------------------------------------------------------------------------moduleControl.Concurrent.SampleVar(-- * Sample VariablesSampleVar,-- :: type _ =newEmptySampleVar,-- :: IO (SampleVar a)newSampleVar,-- :: a -> IO (SampleVar a)emptySampleVar,-- :: SampleVar a -> IO ()readSampleVar,-- :: SampleVar a -> IO awriteSampleVar,-- :: SampleVar a -> a -> IO ()isEmptySampleVar,-- :: SampleVar a -> IO Bool)whereimportPreludeimportControl.Concurrent.MVarimportControl.Exception(mask_)importData.Functor((<$>))-- |-- 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 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 a filled 'SampleVar' overwrites the current value.-- (different from 'putMVar' on full 'MVar'.)newtypeSampleVara=SampleVar(MVar(Int-- 1 == full-- 0 == empty-- <0 no of readers blocked,MVara))deriving(Eq)-- |Build a new, empty, 'SampleVar'newEmptySampleVar::IO(SampleVara)newEmptySampleVar=dov<-newEmptyMVarSampleVar<$>newMVar(0,v)-- |Build a 'SampleVar' with an initial value.newSampleVar::a->IO(SampleVara)newSampleVara=dov<-newMVaraSampleVar<$>newMVar(1,v)-- |If the SampleVar is full, leave it empty. Otherwise, do nothing.emptySampleVar::SampleVara->IO()emptySampleVar(SampleVarv)=mask_$dos@(readers,var)<-takeMVarvifreaders>0thendo_<-takeMVarvarputMVarv(0,var)elseputMVarvs-- |Wait for a value to become available, then take it and return.readSampleVar::SampleVara->IOareadSampleVar(SampleVarsvar)=mask_$do---- filled => make empty and grab sample-- not filled => try to grab value, empty when read val.--(readers,val)<-takeMVarsvarletreaders'=readers-1readers'`seq`putMVarsvar(readers',val)takeMVarval-- |Write a value into the 'SampleVar', overwriting any previous value that-- was there.writeSampleVar::SampleVara->a->IO()writeSampleVar(SampleVarsvar)v=mask_$do---- filled => overwrite-- not filled => fill, write val--s@(readers,val)<-takeMVarsvarcasereadersof1->swapMVarvalv>>putMVarsvars_->putMVarvalv>>letreaders'=min1(readers+1)inreaders'`seq`putMVarsvar(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::SampleVara->IOBoolisEmptySampleVar(SampleVarsvar)=do(readers,_)<-readMVarsvarreturn(readers<=0)