module Z.IO.LowResTimer
(
registerLowResTimer
, registerLowResTimer_
, registerLowResTimerOn
, LowResTimer
, queryLowResTimer
, cancelLowResTimer
, cancelLowResTimer_
, timeoutLowRes
, timeoutLowResEx
, threadDelayLowRes
, throttle
, throttle_
, throttleTrailing_
, LowResTimerManager
, getLowResTimerManager
, isLowResTimerManagerRunning
, lowResTimerManagerCapabilitiesChanged
) where
import Z.Data.Array
import Data.Word
#ifndef mingw32_HOST_OS
import GHC.Event
#endif
import Control.Concurrent
import Control.Monad
import Data.IORef
import GHC.Conc
import System.IO.Unsafe
import Z.Data.PrimRef.PrimIORef
import Z.IO.Exception
import Z.IO.UV.FFI (uv_hrtime)
queueSize :: Int
queueSize :: Int
queueSize = Int
128
data TimerList = TimerItem {-# UNPACK #-} !Counter (IO ()) TimerList | TimerNil
data LowResTimerManager = LowResTimerManager
(Array (IORef TimerList))
(MVar Int)
Counter
(MVar Bool)
newLowResTimerManager :: IO LowResTimerManager
newLowResTimerManager :: IO LowResTimerManager
newLowResTimerManager = do
MVar Int
indexLock <- Int -> IO (MVar Int)
forall a. a -> IO (MVar a)
newMVar Int
0
Counter
regCounter <- Int -> IO Counter
newCounter Int
0
MVar Bool
runningLock <- Bool -> IO (MVar Bool)
forall a. a -> IO (MVar a)
newMVar Bool
False
MutableArray RealWorld (IORef TimerList)
queue <- Int -> IO (MArr Array RealWorld (IORef TimerList))
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
newArr Int
queueSize
[Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..Int
queueSizeInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Int
i -> do
MArr Array RealWorld (IORef TimerList)
-> Int -> IORef TimerList -> IO ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> a -> m ()
writeArr MArr Array RealWorld (IORef TimerList)
MutableArray RealWorld (IORef TimerList)
queue Int
i (IORef TimerList -> IO ()) -> IO (IORef TimerList) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< TimerList -> IO (IORef TimerList)
forall a. a -> IO (IORef a)
newIORef TimerList
TimerNil
Array (IORef TimerList)
iqueue <- MArr Array RealWorld (IORef TimerList)
-> IO (Array (IORef TimerList))
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
unsafeFreezeArr MArr Array RealWorld (IORef TimerList)
MutableArray RealWorld (IORef TimerList)
queue
LowResTimerManager -> IO LowResTimerManager
forall (m :: * -> *) a. Monad m => a -> m a
return (Array (IORef TimerList)
-> MVar Int -> Counter -> MVar Bool -> LowResTimerManager
LowResTimerManager Array (IORef TimerList)
iqueue MVar Int
indexLock Counter
regCounter MVar Bool
runningLock)
lowResTimerManager :: IORef (Array LowResTimerManager)
{-# NOINLINE lowResTimerManager #-}
lowResTimerManager :: IORef (Array LowResTimerManager)
lowResTimerManager = IO (IORef (Array LowResTimerManager))
-> IORef (Array LowResTimerManager)
forall a. IO a -> a
unsafePerformIO (IO (IORef (Array LowResTimerManager))
-> IORef (Array LowResTimerManager))
-> IO (IORef (Array LowResTimerManager))
-> IORef (Array LowResTimerManager)
forall a b. (a -> b) -> a -> b
$ do
Int
numCaps <- IO Int
getNumCapabilities
MutableArray RealWorld LowResTimerManager
lrtmArray <- Int -> IO (MArr Array RealWorld LowResTimerManager)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
newArr Int
numCaps
[Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..Int
numCapsInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Int
i -> do
MArr Array RealWorld LowResTimerManager
-> Int -> LowResTimerManager -> IO ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> a -> m ()
writeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray Int
i (LowResTimerManager -> IO ()) -> IO LowResTimerManager -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO LowResTimerManager
newLowResTimerManager
Array LowResTimerManager
ilrtmArray <- MArr Array RealWorld LowResTimerManager
-> IO (Array LowResTimerManager)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
unsafeFreezeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray
Array LowResTimerManager -> IO (IORef (Array LowResTimerManager))
forall a. a -> IO (IORef a)
newIORef Array LowResTimerManager
ilrtmArray
lowResTimerManagerCapabilitiesChanged :: IO ()
lowResTimerManagerCapabilitiesChanged :: IO ()
lowResTimerManagerCapabilitiesChanged = do
Array LowResTimerManager
lrtmArray <- IORef (Array LowResTimerManager) -> IO (Array LowResTimerManager)
forall a. IORef a -> IO a
readIORef IORef (Array LowResTimerManager)
lowResTimerManager
let oldSize :: Int
oldSize = Array LowResTimerManager -> Int
forall (arr :: * -> *) a. Arr arr a => arr a -> Int
sizeofArr Array LowResTimerManager
lrtmArray
Int
numCaps <- IO Int
getNumCapabilities
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
numCaps Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
oldSize) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
MutableArray RealWorld LowResTimerManager
lrtmArray' <- Int -> IO (MArr Array RealWorld LowResTimerManager)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
Int -> m (MArr arr s a)
newArr Int
numCaps
if Int
numCaps Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
oldSize
then do
[Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..Int
numCapsInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Int
i -> do
MArr Array RealWorld LowResTimerManager
-> Int -> LowResTimerManager -> IO ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> a -> m ()
writeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray' Int
i (LowResTimerManager -> IO ()) -> IO LowResTimerManager -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Array LowResTimerManager -> Int -> IO LowResTimerManager
forall (arr :: * -> *) a (m :: * -> *).
(Arr arr a, Monad m) =>
arr a -> Int -> m a
indexArrM Array LowResTimerManager
lrtmArray Int
i
else do
[Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0..Int
oldSizeInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Int
i -> do
MArr Array RealWorld LowResTimerManager
-> Int -> LowResTimerManager -> IO ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> a -> m ()
writeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray' Int
i (LowResTimerManager -> IO ()) -> IO LowResTimerManager -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Array LowResTimerManager -> Int -> IO LowResTimerManager
forall (arr :: * -> *) a (m :: * -> *).
(Arr arr a, Monad m) =>
arr a -> Int -> m a
indexArrM Array LowResTimerManager
lrtmArray Int
i
[Int] -> (Int -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
oldSize..Int
numCapsInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Int
i -> do
MArr Array RealWorld LowResTimerManager
-> Int -> LowResTimerManager -> IO ()
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> Int -> a -> m ()
writeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray' Int
i (LowResTimerManager -> IO ()) -> IO LowResTimerManager -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO LowResTimerManager
newLowResTimerManager
Array LowResTimerManager
ilrtmArray' <- MArr Array RealWorld LowResTimerManager
-> IO (Array LowResTimerManager)
forall (arr :: * -> *) a (m :: * -> *) s.
(Arr arr a, PrimMonad m, PrimState m ~ s) =>
MArr arr s a -> m (arr a)
unsafeFreezeArr MArr Array RealWorld LowResTimerManager
MutableArray RealWorld LowResTimerManager
lrtmArray'
IORef (Array LowResTimerManager)
-> (Array LowResTimerManager -> (Array LowResTimerManager, ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef (Array LowResTimerManager)
lowResTimerManager ((Array LowResTimerManager -> (Array LowResTimerManager, ()))
-> IO ())
-> (Array LowResTimerManager -> (Array LowResTimerManager, ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \ Array LowResTimerManager
_ -> (Array LowResTimerManager
ilrtmArray', ())
getLowResTimerManager :: IO LowResTimerManager
{-# INLINABLE getLowResTimerManager #-}
getLowResTimerManager :: IO LowResTimerManager
getLowResTimerManager = do
(Int
cap, Bool
_) <- ThreadId -> IO (Int, Bool)
threadCapability (ThreadId -> IO (Int, Bool)) -> IO ThreadId -> IO (Int, Bool)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO ThreadId
myThreadId
Array LowResTimerManager
lrtmArray <- IORef (Array LowResTimerManager) -> IO (Array LowResTimerManager)
forall a. IORef a -> IO a
readIORef IORef (Array LowResTimerManager)
lowResTimerManager
Array LowResTimerManager -> Int -> IO LowResTimerManager
forall (arr :: * -> *) a (m :: * -> *).
(Arr arr a, Monad m) =>
arr a -> Int -> m a
indexArrM Array LowResTimerManager
lrtmArray (Int
cap Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Array LowResTimerManager -> Int
forall (arr :: * -> *) a. Arr arr a => arr a -> Int
sizeofArr Array LowResTimerManager
lrtmArray)
isLowResTimerManagerRunning :: LowResTimerManager -> IO Bool
{-# INLINABLE isLowResTimerManagerRunning #-}
isLowResTimerManagerRunning :: LowResTimerManager -> IO Bool
isLowResTimerManagerRunning (LowResTimerManager Array (IORef TimerList)
_ MVar Int
_ Counter
_ MVar Bool
runningLock) = MVar Bool -> IO Bool
forall a. MVar a -> IO a
readMVar MVar Bool
runningLock
registerLowResTimer :: Int
-> IO ()
-> IO LowResTimer
{-# INLINABLE registerLowResTimer #-}
registerLowResTimer :: Int -> IO () -> IO LowResTimer
registerLowResTimer Int
t IO ()
action = do
LowResTimerManager
lrtm <- IO LowResTimerManager
getLowResTimerManager
LowResTimerManager -> Int -> IO () -> IO LowResTimer
registerLowResTimerOn LowResTimerManager
lrtm Int
t IO ()
action
registerLowResTimer_ :: Int
-> IO ()
-> IO ()
{-# INLINABLE registerLowResTimer_ #-}
registerLowResTimer_ :: Int -> IO () -> IO ()
registerLowResTimer_ Int
t IO ()
action = IO LowResTimer -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Int -> IO () -> IO LowResTimer
registerLowResTimer Int
t IO ()
action)
registerLowResTimerOn :: LowResTimerManager
-> Int
-> IO ()
-> IO LowResTimer
{-# INLINABLE registerLowResTimerOn #-}
registerLowResTimerOn :: LowResTimerManager -> Int -> IO () -> IO LowResTimer
registerLowResTimerOn lrtm :: LowResTimerManager
lrtm@(LowResTimerManager Array (IORef TimerList)
queue MVar Int
indexLock Counter
regCounter MVar Bool
_) Int
t IO ()
action = do
let (Int
round_, Int
tick) = (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
t) Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
queueSize
Int
i <- MVar Int -> IO Int
forall a. MVar a -> IO a
readMVar MVar Int
indexLock
IORef TimerList
tlistRef <- Array (IORef TimerList) -> Int -> IO (IORef TimerList)
forall (arr :: * -> *) a (m :: * -> *).
(Arr arr a, Monad m) =>
arr a -> Int -> m a
indexArrM Array (IORef TimerList)
queue ((Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
tick) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
queueSize)
Counter
roundCounter <- Int -> IO Counter
newCounter Int
round_
IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
IORef TimerList -> (TimerList -> (TimerList, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef TimerList
tlistRef ((TimerList -> (TimerList, ())) -> IO ())
-> (TimerList -> (TimerList, ())) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ TimerList
tlist ->
let newList :: TimerList
newList = Counter -> IO () -> TimerList -> TimerList
TimerItem Counter
roundCounter IO ()
action TimerList
tlist
in (TimerList
newList, ())
Counter -> Int -> IO ()
atomicAddCounter_ Counter
regCounter Int
1
LowResTimerManager -> IO ()
ensureLowResTimerManager LowResTimerManager
lrtm
LowResTimer -> IO LowResTimer
forall (m :: * -> *) a. Monad m => a -> m a
return (Counter -> LowResTimer
LowResTimer Counter
roundCounter)
newtype LowResTimer = LowResTimer Counter
queryLowResTimer :: LowResTimer -> IO Int
{-# INLINABLE queryLowResTimer #-}
queryLowResTimer :: LowResTimer -> IO Int
queryLowResTimer (LowResTimer Counter
c) = Counter -> IO Int
forall a. Prim a => PrimIORef a -> IO a
readPrimIORef Counter
c
cancelLowResTimer :: LowResTimer -> IO Int
{-# INLINABLE cancelLowResTimer #-}
cancelLowResTimer :: LowResTimer -> IO Int
cancelLowResTimer (LowResTimer Counter
c) = Counter -> Int -> IO Int
atomicOrCounter Counter
c (-Int
1)
cancelLowResTimer_ :: LowResTimer -> IO ()
{-# INLINABLE cancelLowResTimer_ #-}
cancelLowResTimer_ :: LowResTimer -> IO ()
cancelLowResTimer_ = IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Int -> IO ())
-> (LowResTimer -> IO Int) -> LowResTimer -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LowResTimer -> IO Int
cancelLowResTimer
timeoutLowRes :: Int
-> IO a
-> IO (Maybe a)
{-# INLINABLE timeoutLowRes #-}
timeoutLowRes :: Int -> IO a -> IO (Maybe a)
timeoutLowRes Int
timeo IO a
io = do
ThreadId
mid <- IO ThreadId
myThreadId
IO (Maybe a) -> (TimeOutException -> IO (Maybe a)) -> IO (Maybe a)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch
(do LowResTimer
timer <- Int -> IO () -> IO LowResTimer
registerLowResTimer Int
timeo (ThreadId -> IO ()
timeoutAThread ThreadId
mid)
a
r <- IO a
io
Int
_ <- LowResTimer -> IO Int
cancelLowResTimer LowResTimer
timer
Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a
forall a. a -> Maybe a
Just a
r))
( \ (TimeOutException
_ :: TimeOutException) -> Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing )
where
timeoutAThread :: ThreadId -> IO ()
timeoutAThread ThreadId
tid = IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> (IO () -> IO ThreadId) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> IO ThreadId
forkIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ ThreadId -> TimeOutException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
tid (ThreadId -> CallStack -> TimeOutException
TimeOutException ThreadId
tid CallStack
forall a. HasCallStack => a
undefined)
timeoutLowResEx :: HasCallStack
=> Int
-> IO a
-> IO a
{-# INLINABLE timeoutLowResEx #-}
timeoutLowResEx :: Int -> IO a -> IO a
timeoutLowResEx Int
timeo IO a
io = do
ThreadId
mid <- IO ThreadId
myThreadId
LowResTimer
timer <- Int -> IO () -> IO LowResTimer
registerLowResTimer Int
timeo (ThreadId -> IO ()
timeoutAThread ThreadId
mid)
a
r <- IO a
io
Int
_ <- LowResTimer -> IO Int
cancelLowResTimer LowResTimer
timer
a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
r
where
timeoutAThread :: ThreadId -> IO ()
timeoutAThread ThreadId
tid = IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> (IO () -> IO ThreadId) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> IO ThreadId
forkIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ ThreadId -> TimeOutException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
tid (ThreadId -> CallStack -> TimeOutException
TimeOutException ThreadId
tid CallStack
HasCallStack => CallStack
callStack)
data TimeOutException = TimeOutException ThreadId CallStack deriving Int -> TimeOutException -> ShowS
[TimeOutException] -> ShowS
TimeOutException -> String
(Int -> TimeOutException -> ShowS)
-> (TimeOutException -> String)
-> ([TimeOutException] -> ShowS)
-> Show TimeOutException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TimeOutException] -> ShowS
$cshowList :: [TimeOutException] -> ShowS
show :: TimeOutException -> String
$cshow :: TimeOutException -> String
showsPrec :: Int -> TimeOutException -> ShowS
$cshowsPrec :: Int -> TimeOutException -> ShowS
Show
instance Exception TimeOutException
threadDelayLowRes :: Int -> IO ()
{-# INLINABLE threadDelayLowRes #-}
threadDelayLowRes :: Int -> IO ()
threadDelayLowRes Int
dsecs = IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
MVar ()
m <- IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
LowResTimer
t <- Int -> IO () -> IO LowResTimer
registerLowResTimer Int
dsecs (MVar () -> () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar ()
m ())
MVar () -> IO ()
forall a. MVar a -> IO a
takeMVar MVar ()
m IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`onException` LowResTimer -> IO ()
cancelLowResTimer_ LowResTimer
t
ensureLowResTimerManager :: LowResTimerManager -> IO ()
{-# INLINABLE ensureLowResTimerManager #-}
ensureLowResTimerManager :: LowResTimerManager -> IO ()
ensureLowResTimerManager lrtm :: LowResTimerManager
lrtm@(LowResTimerManager Array (IORef TimerList)
_ MVar Int
_ Counter
_ MVar Bool
runningLock) = do
MVar Bool -> (Bool -> IO Bool) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar Bool
runningLock ((Bool -> IO Bool) -> IO ()) -> (Bool -> IO Bool) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Bool
running -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
running (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Word64
t <- IO Word64
uv_hrtime
ThreadId
tid <- IO () -> IO ThreadId
forkIO (LowResTimerManager -> Word64 -> IO ()
startLowResTimerManager LowResTimerManager
lrtm Word64
t)
ThreadId -> String -> IO ()
labelThread ThreadId
tid String
"Z-IO: low resolution time manager"
Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
startLowResTimerManager :: LowResTimerManager -> Word64 -> IO ()
startLowResTimerManager :: LowResTimerManager -> Word64 -> IO ()
startLowResTimerManager lrtm :: LowResTimerManager
lrtm@(LowResTimerManager Array (IORef TimerList)
_ MVar Int
_ Counter
regCounter MVar Bool
runningLock) !Word64
stdT = do
MVar Bool -> (Bool -> IO Bool) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar Bool
runningLock ((Bool -> IO Bool) -> IO ()) -> (Bool -> IO Bool) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Bool
_ -> do
Int
c <- Counter -> IO Int
forall a. Prim a => PrimIORef a -> IO a
readPrimIORef Counter
regCounter
if Int
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
then do
Word64
t <- IO Word64
uv_hrtime
let !deltaT :: Int
deltaT = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
t Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
stdT) Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`quot` Word64
1000)) Int
99999
ThreadId
_ <- IO () -> IO ThreadId
forkIO (LowResTimerManager -> IO ()
fireLowResTimerQueue LowResTimerManager
lrtm)
case () of
()
_
#ifndef mingw32_HOST_OS
| Bool
rtsSupportsBoundThreads -> do
TimerManager
htm <- IO TimerManager
getSystemTimerManager
IO TimeoutKey -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO TimeoutKey -> IO ()) -> IO TimeoutKey -> IO ()
forall a b. (a -> b) -> a -> b
$ TimerManager -> Int -> IO () -> IO TimeoutKey
registerTimeout TimerManager
htm (Int
100000 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
deltaT) (LowResTimerManager -> Word64 -> IO ()
startLowResTimerManager LowResTimerManager
lrtm (Word64
stdT Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
100000000))
#endif
| Bool
otherwise -> IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> (IO () -> IO ThreadId) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> IO ThreadId
forkIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Int -> IO ()
threadDelay (Int
100000 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
deltaT)
LowResTimerManager -> Word64 -> IO ()
startLowResTimerManager LowResTimerManager
lrtm (Word64
stdT Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
100000000)
Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
else do
Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
fireLowResTimerQueue :: LowResTimerManager -> IO ()
fireLowResTimerQueue :: LowResTimerManager -> IO ()
fireLowResTimerQueue (LowResTimerManager Array (IORef TimerList)
queue MVar Int
indexLock Counter
regCounter MVar Bool
_) = do
(TimerList
tList, IORef TimerList
tListRef) <- MVar Int
-> (Int -> IO (Int, (TimerList, IORef TimerList)))
-> IO (TimerList, IORef TimerList)
forall a b. MVar a -> (a -> IO (a, b)) -> IO b
modifyMVar MVar Int
indexLock ((Int -> IO (Int, (TimerList, IORef TimerList)))
-> IO (TimerList, IORef TimerList))
-> (Int -> IO (Int, (TimerList, IORef TimerList)))
-> IO (TimerList, IORef TimerList)
forall a b. (a -> b) -> a -> b
$ \ Int
index -> do
IORef TimerList
tListRef <- Array (IORef TimerList) -> Int -> IO (IORef TimerList)
forall (arr :: * -> *) a (m :: * -> *).
(Arr arr a, Monad m) =>
arr a -> Int -> m a
indexArrM Array (IORef TimerList)
queue Int
index
TimerList
tList <- IORef TimerList
-> (TimerList -> (TimerList, TimerList)) -> IO TimerList
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef TimerList
tListRef ((TimerList -> (TimerList, TimerList)) -> IO TimerList)
-> (TimerList -> (TimerList, TimerList)) -> IO TimerList
forall a b. (a -> b) -> a -> b
$ \ TimerList
tList -> (TimerList
TimerNil, TimerList
tList)
let !index' :: Int
index' = (Int
indexInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
queueSize
(Int, (TimerList, IORef TimerList))
-> IO (Int, (TimerList, IORef TimerList))
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
index', (TimerList
tList, IORef TimerList
tListRef))
TimerList -> IORef TimerList -> Counter -> IO ()
go TimerList
tList IORef TimerList
tListRef Counter
regCounter
where
go :: TimerList -> IORef TimerList -> Counter -> IO ()
go (TimerItem Counter
roundCounter IO ()
action TimerList
nextList) IORef TimerList
tListRef Counter
counter = do
Int
r <- Counter -> Int -> IO Int
atomicSubCounter Counter
roundCounter Int
1
case Int
r Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` Int
0 of
Ordering
LT -> do
Counter -> Int -> IO ()
atomicSubCounter_ Counter
counter Int
1
TimerList -> IORef TimerList -> Counter -> IO ()
go TimerList
nextList IORef TimerList
tListRef Counter
counter
Ordering
EQ -> do
Counter -> Int -> IO ()
atomicSubCounter_ Counter
counter Int
1
IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch IO ()
action ( \ (SomeException
_ :: SomeException) -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () )
TimerList -> IORef TimerList -> Counter -> IO ()
go TimerList
nextList IORef TimerList
tListRef Counter
counter
Ordering
GT -> do
IORef TimerList -> (TimerList -> (TimerList, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef TimerList
tListRef ((TimerList -> (TimerList, ())) -> IO ())
-> (TimerList -> (TimerList, ())) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ TimerList
tlist -> (Counter -> IO () -> TimerList -> TimerList
TimerItem Counter
roundCounter IO ()
action TimerList
tlist, ())
TimerList -> IORef TimerList -> Counter -> IO ()
go TimerList
nextList IORef TimerList
tListRef Counter
counter
go TimerList
TimerNil IORef TimerList
_ Counter
_ = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
throttle :: Int
-> IO a
-> IO (IO a)
{-# INLINABLE throttle #-}
throttle :: Int -> IO a -> IO (IO a)
throttle Int
t IO a
action = do
Counter
resultCounter <- Int -> IO Counter
newCounter Int
0
IORef a
resultRef <- a -> IO (IORef a)
forall a. a -> IO (IORef a)
newIORef (a -> IO (IORef a)) -> IO a -> IO (IORef a)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO a
action
IO a -> IO (IO a)
forall (m :: * -> *) a. Monad m => a -> m a
return (IO a -> IO (IO a)) -> IO a -> IO (IO a)
forall a b. (a -> b) -> a -> b
$ do
Int
c <- Counter -> Int -> IO Int
atomicOrCounter Counter
resultCounter (-Int
1)
if Int
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then do
Int -> IO () -> IO ()
registerLowResTimer_ Int
t (IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Int -> IO ()) -> IO Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Counter -> Int -> IO Int
atomicAndCounter Counter
resultCounter Int
0)
!a
r <- IO a
action
IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
atomicWriteIORef IORef a
resultRef a
r
a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
r
else IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
resultRef
throttle_ :: Int
-> IO ()
-> IO (IO ())
{-# INLINABLE throttle_ #-}
throttle_ :: Int -> IO () -> IO (IO ())
throttle_ Int
t IO ()
action = do
Counter
resultCounter <- Int -> IO Counter
newCounter Int
0
IO () -> IO (IO ())
forall (m :: * -> *) a. Monad m => a -> m a
return (IO () -> IO (IO ())) -> IO () -> IO (IO ())
forall a b. (a -> b) -> a -> b
$ do
Int
c <- Counter -> Int -> IO Int
atomicOrCounter Counter
resultCounter (-Int
1)
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Int -> IO () -> IO ()
registerLowResTimer_ Int
t (IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Int -> IO ()) -> IO Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Counter -> Int -> IO Int
atomicAndCounter Counter
resultCounter Int
0)
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void IO ()
action
throttleTrailing_ :: Int
-> IO ()
-> IO (IO ())
{-# INLINABLE throttleTrailing_ #-}
throttleTrailing_ :: Int -> IO () -> IO (IO ())
throttleTrailing_ Int
t IO ()
action = do
Counter
resultCounter <- Int -> IO Counter
newCounter Int
0
IO () -> IO (IO ())
forall (m :: * -> *) a. Monad m => a -> m a
return (IO () -> IO (IO ())) -> IO () -> IO (IO ())
forall a b. (a -> b) -> a -> b
$ do
Int
c <- Counter -> Int -> IO Int
atomicOrCounter Counter
resultCounter (-Int
1)
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (IO () -> IO ()) -> (IO () -> IO ()) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> IO () -> IO ()
registerLowResTimer_ Int
t (IO () -> IO ()) -> (IO () -> IO ()) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> (IO () -> IO ThreadId) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> IO ThreadId
forkIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Counter -> Int -> IO ()
atomicAndCounter_ Counter
resultCounter Int
0
IO ()
action