2020-01-24 08:28:38 +03:00
|
|
|
module Urbit.Timer ( Timer(..), init, stop, start
|
2019-05-09 23:01:22 +03:00
|
|
|
, Sys.getSystemTime, sysTimeGapMicroSecs
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Data.IORef
|
2019-07-12 22:24:44 +03:00
|
|
|
import Prelude hiding (init)
|
2019-05-09 23:01:22 +03:00
|
|
|
|
|
|
|
import qualified Data.Time.Clock.System as Sys
|
2019-07-12 22:24:44 +03:00
|
|
|
import qualified GHC.Event as Ev
|
2019-05-09 23:01:22 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Timer Stuff -----------------------------------------------------------------
|
|
|
|
|
|
|
|
data Timer = Timer
|
|
|
|
{ bState :: IORef (Maybe Ev.TimeoutKey)
|
|
|
|
, bManager :: Ev.TimerManager
|
|
|
|
}
|
|
|
|
|
|
|
|
init :: IO Timer
|
|
|
|
init = do
|
|
|
|
st <- newIORef Nothing
|
|
|
|
man <- Ev.getSystemTimerManager
|
|
|
|
pure (Timer st man)
|
|
|
|
|
|
|
|
sysTimeGapMicroSecs :: Sys.SystemTime -> Sys.SystemTime -> Int
|
|
|
|
sysTimeGapMicroSecs (Sys.MkSystemTime xSec xNs) (Sys.MkSystemTime ySec yNs) =
|
|
|
|
(+) (1_000_000 * fromIntegral (ySec - xSec))
|
|
|
|
((fromIntegral yNs - fromIntegral xNs) `quot` 1000)
|
|
|
|
|
|
|
|
start :: Timer -> Sys.SystemTime -> IO () -> IO ()
|
|
|
|
start timer@(Timer vSt man) time cb = do
|
|
|
|
let fire = cb >> stop timer
|
|
|
|
stop timer
|
|
|
|
now <- Sys.getSystemTime
|
|
|
|
let sleep = sysTimeGapMicroSecs now time
|
2019-08-29 03:26:59 +03:00
|
|
|
-- print (now, time, "->", sleep)
|
|
|
|
if (sleep <= 0) then fire else do
|
2019-05-09 23:01:22 +03:00
|
|
|
key <- Ev.registerTimeout man sleep fire
|
|
|
|
atomicWriteIORef vSt $! Just key
|
|
|
|
|
|
|
|
stop :: Timer -> IO ()
|
|
|
|
stop (Timer vSt man) =
|
|
|
|
atomicModifyIORef' vSt (Nothing,) >>= \case
|
|
|
|
Just key -> Ev.unregisterTimeout man key
|
|
|
|
Nothing -> pure ()
|