@@ -84,6 +84,8 @@ import Control.Monad.Fix (MonadFix (..))
8484
8585import Control.Concurrent.Class.MonadChan hiding (Chan )
8686import Control.Concurrent.Class.MonadChan qualified as MonadAsync
87+ import Control.Concurrent.Class.MonadQSem hiding (QSem )
88+ import Control.Concurrent.Class.MonadQSem qualified as MonadQSem
8789import Control.Concurrent.Class.MonadMVar
8890import Control.Concurrent.Class.MonadSTM.Strict.TVar (StrictTVar )
8991import Control.Concurrent.Class.MonadSTM.Strict.TVar qualified as StrictTVar
@@ -120,7 +122,7 @@ import Data.Bifunctor (bimap)
120122import Data.Dynamic (Dynamic , toDyn )
121123import Data.List.Trace qualified as Trace
122124import Data.Map.Strict (Map )
123- import Data.Maybe (fromMaybe )
125+ import Data.Maybe (fromMaybe , isJust )
124126import Data.Monoid (Endo (.. ))
125127import Data.Semigroup (Max (.. ))
126128import Data.STRef.Lazy
@@ -817,6 +819,61 @@ instance MonadChan (IOSim s) where
817819 xs <- getChanContents ch
818820 return (x: xs)
819821
822+ newtype QSem m = QSem (MVar m (Int , [MVar m () ], [MVar m () ]))
823+
824+ signal
825+ :: MonadMVar m
826+ => (Int , [MVar m () ], [MVar m () ])
827+ -> m (Int , [MVar m () ], [MVar m () ])
828+ signal (i,a1,a2) =
829+ if i == 0
830+ then loop a1 a2
831+ else let ! z = i+ 1 in return (z, a1, a2)
832+ where
833+ loop [] [] = return (1 , [] , [] )
834+ loop [] b2 = loop (reverse b2) []
835+ loop (b: bs) b2 = do
836+ r <- tryPutMVar b ()
837+ if r then return (0 , bs, b2)
838+ else loop bs b2
839+
840+ instance MonadQSem (IOSim s ) where
841+ type QSem (IOSim s ) = QSem (IOSim s )
842+
843+ newQSem initial
844+ | initial < 0 = fail " newQSem: Initial quantity must be non-negative"
845+ | otherwise = do
846+ sem <- newMVar (initial, [] , [] )
847+ return (QSem sem)
848+
849+ waitQSem (QSem m) =
850+ mask_ $ do
851+ (i,b1,b2) <- takeMVar m
852+ if i == 0
853+ then do
854+ b <- newEmptyMVar
855+ putMVar m (i, b1, b: b2)
856+ uninterruptibleWait b
857+ else do
858+ let ! z = i- 1
859+ putMVar m (z, b1, b2)
860+ return ()
861+ where
862+ uninterruptibleWait b =
863+ takeMVar b `onException`
864+ uninterruptibleMask_ (do
865+ (i,b1,b2) <- takeMVar m
866+ r <- tryTakeMVar b
867+ r' <- if isJust r
868+ then signal (i,b1,b2)
869+ else do putMVar b () ; return (i,b1,b2)
870+ putMVar m r')
871+ signalQSem (QSem m) =
872+ uninterruptibleMask_ $ do
873+ r <- takeMVar m
874+ r' <- signal r
875+ putMVar m r'
876+
820877-- | 'Trace' is a recursive data type, it is the trace of a 'IOSim'
821878-- computation. The trace will contain information about thread scheduling,
822879-- blocking on 'TVar's, and other internal state changes of 'IOSim'. More
0 commit comments