module Simulation.Aivika.Trans.GPSS.AssemblySet
(
AssemblySet,
newAssemblySet,
assembleTransact,
gatherTransacts,
transactAssembling,
transactGathering) where
import Data.Monoid
import Data.Maybe
import Data.Hashable
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Trans
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Parameter
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.GPSS.Transact
import Simulation.Aivika.Trans.GPSS.TransactQueueStrategy
data AssemblySet m =
AssemblySet { assemblySetSequenceNo :: Int,
assemblySetAssemblingTransact :: Ref m (Maybe (ProcessId m)),
assemblySetAssemblingCounter :: Ref m Int,
assemblySetGatheringTransacts :: StrategyQueue m (TransactQueueStrategy FCFS) (ProcessId m),
assemblySetGatheringCounter :: Ref m Int
}
instance MonadDES m => Eq (AssemblySet m) where
x == y = (assemblySetAssemblingTransact x) == (assemblySetAssemblingTransact y)
instance Hashable (AssemblySet m) where
hashWithSalt salt x = hashWithSalt salt (assemblySetSequenceNo x)
newAssemblySet :: MonadDES m => Simulation m (AssemblySet m)
newAssemblySet =
Simulation $ \r ->
do let g = runGenerator r
sequenceNo <- generateSequenceNo g
assemblingTransact <- invokeSimulation r $ newRef Nothing
assemblingCounter <- invokeSimulation r $ newRef 0
gatheringTransacts <- invokeSimulation r $ newStrategyQueue (TransactQueueStrategy FCFS)
gatheringCounter <- invokeSimulation r $ newRef 0
return AssemblySet { assemblySetSequenceNo = sequenceNo,
assemblySetAssemblingTransact = assemblingTransact,
assemblySetAssemblingCounter = assemblingCounter,
assemblySetGatheringTransacts = gatheringTransacts,
assemblySetGatheringCounter = gatheringCounter
}
assembleTransact :: MonadDES m => Transact m a -> Int -> Process m ()
assembleTransact t n =
do (s, a) <-
liftEvent $
do s <- transactAssemblySet t
a <- readRef (assemblySetAssemblingCounter s)
return (s, a)
if a == 0
then do let n' = n 1
when (n' < 0) $
throwProcess $
SimulationRetry
"The number of transacts must be positive: assembleTransact"
if n' == 0
then return ()
else do liftEvent $
do pid <- requireTransactProcessId t
writeRef (assemblySetAssemblingTransact s) (Just pid)
writeRef (assemblySetAssemblingCounter s) $! n'
passivateProcess
else do let a' = a 1
if a' == 0
then do liftEvent $
do Just pid <- readRef (assemblySetAssemblingTransact s)
writeRef (assemblySetAssemblingTransact s) Nothing
writeRef (assemblySetAssemblingCounter s) $! a'
reactivateProcessImmediately pid
cancelProcess
else do liftEvent $ writeRef (assemblySetAssemblingCounter s) $! a'
cancelProcess
gatherTransacts :: MonadDES m => Transact m a -> Int -> Process m ()
gatherTransacts t n =
do (s, a) <-
liftEvent $
do s <- transactAssemblySet t
a <- readRef (assemblySetGatheringCounter s)
return (s, a)
if a == 0
then do let n' = n 1
when (n' < 0) $
throwProcess $
SimulationRetry
"The number of transacts must be positive: gatherTransacts"
if n' == 0
then return ()
else do liftEvent $
do pid <- requireTransactProcessId t
strategyEnqueueWithPriority
(assemblySetGatheringTransacts s)
(transactPriority t)
pid
writeRef (assemblySetGatheringCounter s) $! n'
passivateProcess
else do let a' = a 1
liftEvent $
do pid <- requireTransactProcessId t
strategyEnqueueWithPriority
(assemblySetGatheringTransacts s)
(transactPriority t)
pid
writeRef (assemblySetGatheringCounter s) $! a'
if a' == 0
then passivateProcessBefore $
liftEvent $
do let loop acc =
do f <- strategyQueueNull (assemblySetGatheringTransacts s)
if f
then return (reverse acc)
else do x <- strategyDequeue (assemblySetGatheringTransacts s)
loop (x: acc)
act [] = return ()
act (pid: pids') =
do reactivateProcessImmediately pid
yieldEvent $ act pids'
pids <- loop []
act pids
else passivateProcess
transactAssembling :: MonadDES m => Transact m a -> Event m Bool
transactAssembling t =
do s <- transactAssemblySet t
a <- readRef (assemblySetAssemblingCounter s)
return (a > 0)
transactGathering :: MonadDES m => Transact m a -> Event m Bool
transactGathering t =
do s <- transactAssemblySet t
a <- readRef (assemblySetGatheringCounter s)
return (a > 0)