module Eventloop.System.EventloopThread where
import Control.DeepSeq
import Control.Exception
import Control.Monad
import Control.Concurrent.ExceptionUtility
import Control.Concurrent.MVar
import Control.Concurrent.STM
import Control.Concurrent.Datastructures.BlockingConcurrentQueue
import Data.Maybe
import Eventloop.System.Processing
import Eventloop.Types.Common
import Eventloop.Types.Exception
import Eventloop.Types.Events
import Eventloop.Types.System
startEventlooping :: EventloopSystemConfiguration progstateT
-> IO ()
startEventlooping systemConfig
= handle
( \exception ->
case (fromException exception) of
(Just RequestShutdownException) -> throwIO RequestShutdownException
_ -> throwIO (EventloopException exception)
)
( do
putInBlockingConcurrentQueue inEventQueue_ Start
forever $ do
inEvent <- takeFromBlockingConcurrentQueue inEventQueue_
processedInEvents <- processEvents "Preprocessing" systemConfig modulePreprocessors [inEvent]
outEvents <- eventloopSteps eventloop progstateT_ processedInEvents
processedOutEvents <- processEvents "Postprocessing" systemConfig modulePostprocessors outEvents
evaluatedOutEvents <- evaluate $ force processedOutEvents
putAllInBlockingConcurrentQueue outEventQueue_ processedOutEvents
)
where
eventloopConfig_ = eventloopConfig systemConfig
eventloop = eventloopFunc eventloopConfig_
progstateT_ = progstateT eventloopConfig_
inEventQueue_ = inEventQueue eventloopConfig_
outEventQueue_ = outEventQueue eventloopConfig_
moduleConfigurations_ = moduleConfigs systemConfig
modulePreprocessors = findProcessors moduleConfigurations_ preprocessorM
modulePostprocessors = findProcessors moduleConfigurations_ postprocessorM
findProcessors :: [EventloopModuleConfiguration]
-> (EventloopModuleConfiguration -> Maybe (SharedIOConstants -> TVar SharedIOState -> IOConstants -> TVar IOState -> event -> IO [event]))
-> [(EventloopModuleIdentifier, IOConstants, TVar IOState, (SharedIOConstants -> TVar SharedIOState -> IOConstants -> TVar IOState -> event -> IO [event]))]
findProcessors moduleConfigs getProcessorFunc
= moduleProcessors
where
moduleProcessorsM = map (\moduleConfig -> (moduleId moduleConfig, ioConstants moduleConfig, ioStateT moduleConfig, getProcessorFunc moduleConfig)) moduleConfigs
moduleProcessorsJ = filter (\(_, _, _, processFuncM) -> isJust processFuncM) moduleProcessorsM
moduleProcessors = map (\(id, ioConst, iostate, (Just processFunc)) -> (id, ioConst, iostate, processFunc)) moduleProcessorsJ
eventloopSteps :: (progstateT -> In -> (progstateT, [Out]))
-> TVar progstateT
-> [In]
-> IO [Out]
eventloopSteps eventloop progstateT inEvents
= sequencedSteps >>= (return.concat)
where
inEventSteps = map (eventloopStep eventloop progstateT) inEvents
sequencedSteps = sequence inEventSteps
eventloopStep :: (progstateT -> In -> (progstateT, [Out]))
-> TVar progstateT
-> In
-> IO [Out]
eventloopStep eventloop progStateT inEvent
= do
progState <- readTVarIO progStateT
let
(progState', outEvents) = eventloop progState inEvent
atomically $ writeTVar progStateT progState'
return outEvents