X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=Control%2FConcurrent%2FMVar.hs;h=9a95b8ff0817236d34d952bd8e0673da8c6b2f97;hb=41e8fba828acbae1751628af50849f5352b27873;hp=7832c2eca38172dd683743d6716cd8646cd381a4;hpb=7f1f4e7a695c402ddd3a1dc2cc7114e649a78ebc;p=ghc-base.git diff --git a/Control/Concurrent/MVar.hs b/Control/Concurrent/MVar.hs index 7832c2e..9a95b8f 100644 --- a/Control/Concurrent/MVar.hs +++ b/Control/Concurrent/MVar.hs @@ -1,95 +1,123 @@ +{-# LANGUAGE CPP, NoImplicitPrelude #-} + ----------------------------------------------------------------------------- --- +-- | -- Module : Control.Concurrent.MVar -- Copyright : (c) The University of Glasgow 2001 --- License : BSD-style (see the file libraries/core/LICENSE) +-- License : BSD-style (see the file libraries/base/LICENSE) -- -- Maintainer : libraries@haskell.org -- Stability : experimental --- Portability : non-portable --- --- $Id: MVar.hs,v 1.1 2001/06/28 14:15:02 simonmar Exp $ +-- Portability : non-portable (concurrency) -- --- MVars: Synchronising variables +-- Synchronising variables -- ----------------------------------------------------------------------------- module Control.Concurrent.MVar - ( 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 - , addMVarFinalizer -- :: MVar a -> IO () -> IO () + ( + -- * @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 ConcBase ( MVar, newEmptyMVar, newMVar, takeMVar, putMVar, - tryTakeMVar, tryPutMVar, isEmptyMVar, - readMVar, swapMVar, - ) -import Prelude hiding( catch ) +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 - ) +import GHC.MVar ( MVar, newEmptyMVar, newMVar, takeMVar, putMVar, + tryTakeMVar, tryPutMVar, isEmptyMVar, addMVarFinalizer + ) #endif -import Control.Exception as Exception - -#ifdef __HUGS__ --- This is as close as Hugs gets to providing throw -throw :: Exception -> IO a -throw = throwIO +#ifdef __GLASGOW_HASKELL__ +import GHC.Base +#else +import Prelude #endif -#ifdef __GLASGOW_HASKELL__ +import Control.Exception.Base + +{-| + 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 + mask_ $ do a <- takeMVar m putMVar m a return a +{-| + Take a value from an 'MVar', put a new value into the 'MVar' and + return the value taken. Note that there is a race condition whereby + another process can put something in the 'MVar' after the take + happens but before the put does. +-} swapMVar :: MVar a -> a -> IO a -swapMVar mvar new = modifyMVar mvar (\old -> return (new,old)) -#endif +swapMVar mvar new = + mask_ $ do + old <- takeMVar mvar + putMVar mvar new + return old --- put back the same value, return something +{-| + '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 +withMVar m io = + mask $ \restore -> do a <- takeMVar m - b <- Exception.catch (unblock (io a)) - (\e -> do putMVar m a; throw e) + b <- restore (io a) `onException` putMVar m a putMVar m a return b --- put back a new value, return () +{-| + 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 +modifyMVar_ m io = + mask $ \restore -> do a <- takeMVar m - a' <- Exception.catch (unblock (io a)) - (\e -> do putMVar m a; throw e) + a' <- restore (io a) `onException` putMVar m a putMVar m a' --- put back a new value, return something +{-| + 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 +modifyMVar m io = + mask $ \restore -> do a <- takeMVar m - (a',b) <- Exception.catch (unblock (io a)) - (\e -> do putMVar m a; throw e) + (a',b) <- restore (io a) `onException` putMVar m a putMVar m a' return b