-----------------------------------------------------------------------------
-- |
-- Module : Control.Concurrent.MVar
-- Copyright : (c) The University of Glasgow 2001
-- License : BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer : [email protected]
-- Stability : experimental
-- Portability : non-portable (concurrency)
--
-- Synchronising variables
--
-----------------------------------------------------------------------------
module Control.Concurrent.MVar
(
-- * @MVar@s
MVar -- abstract
, newEmptyMVar -- :: IO (MVar a)
, newMVar -- :: a -> IO (MVar a)
, takeMVar -- :: MVar a -> IO a
, putMVar -- :: MVar a -> a -> IO ()
, readMVar -- :: MVar a -> IO a
, swapMVar -- :: MVar a -> a -> IO a
, tryTakeMVar -- :: MVar a -> IO (Maybe a)
, tryPutMVar -- :: MVar a -> a -> IO Bool
, isEmptyMVar -- :: MVar a -> IO Bool
, withMVar -- :: MVar a -> (a -> IO b) -> IO b
, modifyMVar_ -- :: MVar a -> (a -> IO a) -> IO ()
, modifyMVar -- :: MVar a -> (a -> IO (a,b)) -> IO b
#ifndef __HUGS__
, addMVarFinalizer -- :: MVar a -> IO () -> IO ()
#endif
) where
#ifdef __HUGS__
import Hugs.ConcBase ( MVar, newEmptyMVar, newMVar, takeMVar, putMVar,
tryTakeMVar, tryPutMVar, isEmptyMVar,
)
#endif
#ifdef __GLASGOW_HASKELL__
import GHC.Conc ( MVar, newEmptyMVar, newMVar, takeMVar, putMVar,
tryTakeMVar, tryPutMVar, isEmptyMVar, addMVarFinalizer
)
#endif
import Prelude
import Control.Exception as Exception
{-|
This is a combination of 'takeMVar' and 'putMVar'; ie. it takes the value
from the 'MVar', puts it back, and also returns it.
-}
readMVar :: MVar a -> IO a
readMVar m =
block $ do
a <- takeMVar m
putMVar m a
return a
-- |Swap the contents of an 'MVar' for a new value.
swapMVar :: MVar a -> a -> IO a
swapMVar mvar new =
block $ do
old <- takeMVar mvar
putMVar mvar new
return old
{-|
'withMVar' is a safe wrapper for operating on the contents of an
'MVar'. This operation is exception-safe: it will replace the
original contents of the 'MVar' if an exception is raised (see
"Control.Exception").
-}
{-# INLINE withMVar #-}
-- inlining has been reported to have dramatic effects; see
-- http://www.haskell.org//pipermail/haskell/2006-May/017907.html
withMVar :: MVar a -> (a -> IO b) -> IO b
withMVar m io =
block $ do
a <- takeMVar m
b <- Exception.catch (unblock (io a))
(\e -> do putMVar m a; throw e)
putMVar m a
return b
{-|
A safe wrapper for modifying the contents of an 'MVar'. Like 'withMVar',
'modifyMVar' will replace the original contents of the 'MVar' if an
exception is raised during the operation.
-}
{-# INLINE modifyMVar_ #-}
modifyMVar_ :: MVar a -> (a -> IO a) -> IO ()
modifyMVar_ m io =
block $ do
a <- takeMVar m
a' <- Exception.catch (unblock (io a))
(\e -> do putMVar m a; throw e)
putMVar m a'
{-|
A slight variation on 'modifyMVar_' that allows a value to be
returned (@b@) in addition to the modified value of the 'MVar'.
-}
{-# INLINE modifyMVar #-}
modifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b
modifyMVar m io =
block $ do
a <- takeMVar m
(a',b) <- Exception.catch (unblock (io a))
(\e -> do putMVar m a; throw e)
putMVar m a'
return b
|