@@ -86,6 +86,8 @@ import Control.Concurrent.Class.MonadChan hiding (Chan)
8686import Control.Concurrent.Class.MonadChan qualified as MonadAsync
8787import Control.Concurrent.Class.MonadQSem hiding (QSem )
8888import Control.Concurrent.Class.MonadQSem qualified as MonadQSem
89+ import Control.Concurrent.Class.MonadQSemN hiding (QSemN )
90+ import Control.Concurrent.Class.MonadQSemN qualified as MonadQSemN
8991import Control.Concurrent.Class.MonadMVar
9092import Control.Concurrent.Class.MonadSTM.Strict.TVar (StrictTVar )
9193import Control.Concurrent.Class.MonadSTM.Strict.TVar qualified as StrictTVar
@@ -874,6 +876,57 @@ instance MonadQSem (IOSim s) where
874876 r' <- signal r
875877 putMVar m r'
876878
879+ newtype QSemN m = QSemN (MVar m (Int , [(Int , MVar m () )], [(Int , MVar m () )]))
880+
881+ data MaybeMV m a = JustMV ! (MVarDefault m a )
882+ | NothingMV
883+
884+ instance MonadQSemN (IOSim s ) where
885+ type QSemN (IOSim s ) = QSemN (IOSim s )
886+
887+ newQSemN initial
888+ | initial < 0 = fail " newQSemN: Initial quantity must be non-negative"
889+ | otherwise = do
890+ sem <- newMVar (initial, [] , [] )
891+ return (QSemN sem)
892+
893+ waitQSemN qs@ (QSemN m) sz = mask_ $ do
894+ mmvar <- modifyMVar m $ \ (i,b1,b2) -> do
895+ let z = i- sz
896+ if z < 0
897+ then do
898+ b <- newEmptyMVar
899+ return ((i, b1, (sz,b): b2), JustMV b)
900+ else return ((z, b1, b2), NothingMV )
901+
902+ case mmvar of
903+ NothingMV -> return ()
904+ JustMV b -> wait' b
905+ where
906+ wait' :: MVar (IOSim s ) () -> IOSim s ()
907+ wait' b =
908+ takeMVar b `onException` do
909+ already_filled <- not <$> tryPutMVar b ()
910+ when already_filled $ signalQSemN qs sz
911+
912+ signalQSemN (QSemN m) sz0 = do
913+ unit <- modifyMVar m $ \ (i,a1,a2) -> loop (sz0 + i) a1 a2
914+
915+ evaluate unit
916+ where
917+ loop 0 bs b2 = return ((0 , bs, b2), () )
918+ loop sz [] [] = return ((sz, [] , [] ), () )
919+ loop sz [] b2 = loop sz (reverse b2) []
920+ loop sz ((j,b): bs) b2
921+ | j > sz = do
922+ r <- isEmptyMVar b
923+ if r then return ((sz, (j,b): bs, b2), () )
924+ else loop sz bs b2
925+ | otherwise = do
926+ r <- tryPutMVar b ()
927+ if r then loop (sz- j) bs b2
928+ else loop sz bs b2
929+
877930-- | 'Trace' is a recursive data type, it is the trace of a 'IOSim'
878931-- computation. The trace will contain information about thread scheduling,
879932-- blocking on 'TVar's, and other internal state changes of 'IOSim'. More
0 commit comments