module Simulation.Aivika.Trans.Resource
(
FCFSResource,
LCFSResource,
SIROResource,
PriorityResource,
Resource,
newFCFSResource,
newFCFSResourceWithMaxCount,
newLCFSResource,
newLCFSResourceWithMaxCount,
newSIROResource,
newSIROResourceWithMaxCount,
newPriorityResource,
newPriorityResourceWithMaxCount,
newResource,
newResourceWithMaxCount,
resourceStrategy,
resourceMaxCount,
resourceCount,
requestResource,
requestResourceWithPriority,
tryRequestResourceWithinEvent,
releaseResource,
releaseResourceWithinEvent,
usingResource,
usingResourceWithPriority) where
import Control.Monad
import Control.Monad.Trans
import Control.Exception
import Simulation.Aivika.Trans.Session
import Simulation.Aivika.Trans.ProtoRef
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Internal.Cont
import Simulation.Aivika.Trans.Internal.Process
import Simulation.Aivika.Trans.QueueStrategy
import qualified Simulation.Aivika.Trans.DoubleLinkedList as DLL
import qualified Simulation.Aivika.Trans.Vector as V
import qualified Simulation.Aivika.Trans.PriorityQueue as PQ
type FCFSResource m = Resource m FCFS
type LCFSResource m = Resource m LCFS
type SIROResource m = Resource m SIRO
type PriorityResource m = Resource m StaticPriorities
data Resource m s =
Resource { resourceStrategy :: s,
resourceMaxCount :: Maybe Int,
resourceCountRef :: ProtoRef m Int,
resourceWaitList :: StrategyQueue m s (Event m (Maybe (ContParams m ()))) }
newFCFSResource :: MonadComp m
=> Int
-> Simulation m (FCFSResource m)
newFCFSResource = newResource FCFS
newFCFSResourceWithMaxCount :: MonadComp m
=> Int
-> Maybe Int
-> Simulation m (FCFSResource m)
newFCFSResourceWithMaxCount = newResourceWithMaxCount FCFS
newLCFSResource :: MonadComp m
=> Int
-> Simulation m (LCFSResource m)
newLCFSResource = newResource LCFS
newLCFSResourceWithMaxCount :: MonadComp m
=> Int
-> Maybe Int
-> Simulation m (LCFSResource m)
newLCFSResourceWithMaxCount = newResourceWithMaxCount LCFS
newSIROResource :: MonadComp m
=> Int
-> Simulation m (SIROResource m)
newSIROResource = newResource SIRO
newSIROResourceWithMaxCount :: MonadComp m
=> Int
-> Maybe Int
-> Simulation m (SIROResource m)
newSIROResourceWithMaxCount = newResourceWithMaxCount SIRO
newPriorityResource :: MonadComp m
=> Int
-> Simulation m (PriorityResource m)
newPriorityResource = newResource StaticPriorities
newPriorityResourceWithMaxCount :: MonadComp m
=> Int
-> Maybe Int
-> Simulation m (PriorityResource m)
newPriorityResourceWithMaxCount = newResourceWithMaxCount StaticPriorities
newResource :: (MonadComp m, QueueStrategy m s)
=> s
-> Int
-> Simulation m (Resource m s)
newResource s count =
Simulation $ \r ->
do when (count < 0) $
error $
"The resource count cannot be negative: " ++
"newResource."
let session = runSession r
countRef <- newProtoRef session count
waitList <- invokeSimulation r $ newStrategyQueue s
return Resource { resourceStrategy = s,
resourceMaxCount = Just count,
resourceCountRef = countRef,
resourceWaitList = waitList }
newResourceWithMaxCount :: (MonadComp m, QueueStrategy m s)
=> s
-> Int
-> Maybe Int
-> Simulation m (Resource m s)
newResourceWithMaxCount s count maxCount =
Simulation $ \r ->
do when (count < 0) $
error $
"The resource count cannot be negative: " ++
"newResourceWithMaxCount."
case maxCount of
Just maxCount | count > maxCount ->
error $
"The resource count cannot be greater than " ++
"its maximum value: newResourceWithMaxCount."
_ ->
return ()
let session = runSession r
countRef <- newProtoRef session count
waitList <- invokeSimulation r $ newStrategyQueue s
return Resource { resourceStrategy = s,
resourceMaxCount = maxCount,
resourceCountRef = countRef,
resourceWaitList = waitList }
resourceCount :: MonadComp m => Resource m s -> Event m Int
resourceCount r =
Event $ \p -> readProtoRef (resourceCountRef r)
requestResource :: (MonadComp m, EnqueueStrategy m s)
=> Resource m s
-> Process m ()
requestResource r =
Process $ \pid ->
Cont $ \c ->
Event $ \p ->
do a <- readProtoRef (resourceCountRef r)
if a == 0
then do c <- invokeEvent p $ contFreeze c
invokeEvent p $
strategyEnqueue (resourceWaitList r) c
else do let a' = a 1
a' `seq` writeProtoRef (resourceCountRef r) a'
invokeEvent p $ resumeCont c ()
requestResourceWithPriority :: (MonadComp m, PriorityQueueStrategy m s p)
=> Resource m s
-> p
-> Process m ()
requestResourceWithPriority r priority =
Process $ \pid ->
Cont $ \c ->
Event $ \p ->
do a <- readProtoRef (resourceCountRef r)
if a == 0
then do c <- invokeEvent p $ contFreeze c
invokeEvent p $
strategyEnqueueWithPriority (resourceWaitList r) priority c
else do let a' = a 1
a' `seq` writeProtoRef (resourceCountRef r) a'
invokeEvent p $ resumeCont c ()
releaseResource :: (MonadComp m, DequeueStrategy m s)
=> Resource m s
-> Process m ()
releaseResource r =
Process $ \_ ->
Cont $ \c ->
Event $ \p ->
do invokeEvent p $ releaseResourceWithinEvent r
invokeEvent p $ resumeCont c ()
releaseResourceWithinEvent :: (MonadComp m, DequeueStrategy m s)
=> Resource m s
-> Event m ()
releaseResourceWithinEvent r =
Event $ \p ->
do a <- readProtoRef (resourceCountRef r)
let a' = a + 1
case resourceMaxCount r of
Just maxCount | a' > maxCount ->
error $
"The resource count cannot be greater than " ++
"its maximum value: releaseResourceWithinEvent."
_ ->
return ()
f <- invokeEvent p $
strategyQueueNull (resourceWaitList r)
if f
then a' `seq` writeProtoRef (resourceCountRef r) a'
else do c <- invokeEvent p $
strategyDequeue (resourceWaitList r)
c <- invokeEvent p c
case c of
Nothing ->
invokeEvent p $ releaseResourceWithinEvent r
Just c ->
invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()
tryRequestResourceWithinEvent :: MonadComp m
=> Resource m s
-> Event m Bool
tryRequestResourceWithinEvent r =
Event $ \p ->
do a <- readProtoRef (resourceCountRef r)
if a == 0
then return False
else do let a' = a 1
a' `seq` writeProtoRef (resourceCountRef r) a'
return True
usingResource :: (MonadComp m, EnqueueStrategy m s)
=> Resource m s
-> Process m a
-> Process m a
usingResource r m =
do requestResource r
finallyProcess m $ releaseResource r
usingResourceWithPriority :: (MonadComp m, PriorityQueueStrategy m s p)
=> Resource m s
-> p
-> Process m a
-> Process m a
usingResourceWithPriority r priority m =
do requestResourceWithPriority r priority
finallyProcess m $ releaseResource r