----------------------------------------------------------------------------- -- | -- Module : Control.Concurrent.AdvSTM.TVar -- Copyright : (c) Peter Robinson 2009 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Peter Robinson -- Stability : experimental -- Portability : non-portable (requires STM) -- -- -- ----------------------------------------------------------------------------- module Control.Concurrent.AdvSTM.TVar( -- * TVars TVar , newTVar , newTVarIO , readTVar , writeTVar , readTVarAsync , writeTVarAsync ) where import Control.Monad.AdvSTM.Class (readTVar,writeTVar,newTVar,TVar(TVar),valueTVar,readTVarAsync,writeTVarAsync) import qualified Control.Concurrent.STM.TVar as OldTVar import qualified Control.Concurrent.STM.TMVar as OldTMVar import Control.Monad(liftM,ap) {- import qualified Control.Concurrent.STM as STM import qualified Control.Concurrent.STM.TChan as OldTChan import Control.Exception(throw,Deadlock(Deadlock)) import Control.Concurrent.AdvSTM(liftAdv,orElse,retry,readTVar,writeTVar,newTVar) import Control.Monad.AdvSTM.Def(AdvSTM(AdvSTM),transThreadId,listeners,TVarValue(TVarValue)) import Control.Concurrent(ThreadId) import Control.Monad.Reader(asks) import Data.Maybe(isJust,Maybe,fromJust) import qualified Data.Set as S -} -------------------------------------------------------------------------------- -- | See 'OldTVar.newTVarIO' -- newTVarIO :: a -> IO (TVar a) newTVarIO a = TVar `liftM` OldTVar.newTVarIO a `ap` OldTMVar.newTMVarIO () `ap` OldTVar.newTVarIO Nothing -------------------------------------------------------------------------------- {- -- | See 'OldTVar.newTVar' newTVar :: a -> AdvSTM (TVar a) newTVar a = TVar `liftM` (liftAdv $ OldTVar.newTVar a) `ap` (liftAdv $ OldTMVar.newTMVar ()) `ap` (liftAdv $ OldTVar.newTVar Nothing) -} {- -------------------------------------------------------------------------------- -- | Writes a value to a TVar. Blocks until the onCommit IO-action(s) are -- complete. See 'onCommit' for details. writeTVar :: TVar a -> a -> AdvSTM () writeTVar tvar a = do commitLock <- liftAdv $ OldTMVar.tryTakeTMVar (onCommitLock tvar) -- Get ThreadID of current transaction: curTid <- AdvSTM $ asks transThreadId storedTid <- liftAdv $ OldTVar.readTVar (currentTid tvar) case commitLock of Nothing -> do if isJust storedTid && fromJust storedTid == curTid then throw Deadlock -- No transaction during onCommit-phase! else retry Just _ -> do unless (isJust storedTid && (fromJust storedTid == curTid)) $ do -- First write access, update the ThreadId: liftAdv $ OldTVar.writeTVar (currentTid tvar) $ Just curTid -- Add this TVar to the onCommit-listener list: lsTVar <- AdvSTM $ asks listeners ls <- liftAdv $ OldTVar.readTVar lsTVar -- Remember the old value for rollback: oldval <- liftAdv $ OldTVar.readTVar (valueTVar tvar) liftAdv $ OldTVar.writeTVar lsTVar $ (onCommitLock tvar,TVarValue (valueTVar tvar,oldval)) : ls liftAdv $ OldTVar.writeTVar (valueTVar tvar) a liftAdv $ OldTMVar.putTMVar (onCommitLock tvar) () -------------------------------------------------------------------------------- -- | Reads a value from a TVar. Blocks until the IO onCommit action(s) of -- the corresponding transaction are complete. -- See 'onCommit' for a more detailed description of this behaviour. readTVar :: TVar a -> AdvSTM a readTVar tvar = do commitLock <- liftAdv $ OldTMVar.tryTakeTMVar (onCommitLock tvar) case commitLock of Nothing -> do storedTid <- liftAdv $ OldTVar.readTVar (currentTid tvar) curTid <- AdvSTM $ asks transThreadId if isJust storedTid && fromJust storedTid == curTid then throw Deadlock else retry Just _ -> do result <- liftAdv $ OldTVar.readTVar $ valueTVar tvar liftAdv $ OldTMVar.putTMVar (onCommitLock tvar) () return result -------------------------------------------------------------------------------- -}