import BasePrelude hiding ((.)) import RealTimeQueue as Q import Control.Monad.IO.Class import Control.Monad.State import System.Clock data LoopState = LoopState { _queue :: Queue String, _lastAction :: TimeSpec, _beforeActing :: TimeSpec } type Loop r = StateT LoopState IO r main :: IO () main = void $ runStateT (queueSomeStuff >> mainLoop) (LoopState createQueue (TimeSpec 0 0) (TimeSpec 0 0)) where queueSomeStuff = do now <- liftIO $ getTime Monotonic modify $ \s -> s { _beforeActing = now, _lastAction = now } forM_ [1,2,4,8,9,10,11,12] $ \i -> queueAction $ scheduleEventIO (TimeSpec i 0, "hello world " ++ show i) mainLoop :: Loop () mainLoop = do queueAction $ runScheduledIO tickTime runner unlessEmptyQueue $ do liftIO $ threadDelay' tickTime mainLoop queueAction :: (Queue String -> Loop (Queue String)) -> Loop () queueAction act = do q <- gets _queue act q >>= \q' -> modify $ \s -> s { _queue = q' } tickTime :: TimeSpec tickTime = TimeSpec 0 1000 threadDelay' :: TimeSpec -> IO () threadDelay' = threadDelay . fromIntegral . timeSpecAsNanoSecs timeSpecAsDouble :: TimeSpec -> Double timeSpecAsDouble ts = x / (10^(9::Int)) where x = fromIntegral $ timeSpecAsNanoSecs ts runner :: (TimeSpec, String) -> Loop () runner (delay, str) = do before <- gets _lastAction muchBefore <- gets _beforeActing after <- liftIO $ do threadDelay' delay now <- liftIO $ getTime Monotonic print (now, str, timeSpecAsDouble $ now - before, timeSpecAsDouble $ now - muchBefore) return now modify $ \s -> s { _lastAction = after } unlessEmptyQueue :: Loop () -> Loop () unlessEmptyQueue f = do q <- gets _queue unless (Q.null q) f