{-# LANGUAGE CPP #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE RecordWildCards #-}
module System.TimeManager (
Manager,
defaultManager,
TimeoutAction,
Handle,
emptyHandle,
initialize,
stopManager,
killManager,
withManager,
withManager',
withHandle,
withHandleKillThread,
tickle,
pause,
resume,
cancel,
register,
registerKillThread,
TimeoutThread (..),
) where
import Control.Concurrent (forkIO, mkWeakThreadId, myThreadId, newMVar)
import qualified Control.Exception as E
import Control.Monad (void, when)
import Data.Bits (shiftR)
import qualified Data.IORef as I
import Data.Word (Word64)
import GHC.Clock (getMonotonicTimeNSec)
import System.IO.Unsafe (unsafePerformIO)
import System.Mem.Weak (deRefWeak)
import System.TimeManager.Internal
#if defined(mingw32_HOST_OS)
import qualified System.TimeManager.Windows as EV
#else
import qualified GHC.Event as EV
#endif
defaultManager :: Manager
defaultManager :: Manager
defaultManager = Int -> Manager
Manager Int
0
emptyHandle :: Handle
emptyHandle :: Handle
emptyHandle =
Handle
{ handleTimeout :: Int
handleTimeout = Int
0
, handleAction :: TimeoutAction
handleAction = () -> TimeoutAction
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
, handleTimerManager :: TimerManager
handleTimerManager = [Char] -> TimerManager
forall {a}. [Char] -> a
mutError [Char]
"handleTimerManager"
, handleState :: IORef HandleState
handleState = [Char] -> IORef HandleState
forall {a}. [Char] -> a
mutError [Char]
"handleState"
, handleLastRenewed :: IORef Word64
handleLastRenewed = [Char] -> IORef Word64
forall {a}. [Char] -> a
mutError [Char]
"handleLastRenewed"
, handleMinRenewGap :: Word64
handleMinRenewGap = Word64
0
, handleLock :: Lock
handleLock = Lock
emptyLock
}
where
mutError :: [Char] -> a
mutError [Char]
s = [Char] -> a
forall a. HasCallStack => [Char] -> a
error ([Char] -> a) -> [Char] -> a
forall a b. (a -> b) -> a -> b
$ [Char]
"time-manager: Handle." [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
s [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" not set"
emptyLock :: Lock
emptyLock :: Lock
emptyLock = IO Lock -> Lock
forall a. IO a -> a
unsafePerformIO (IO Lock -> Lock) -> IO Lock -> Lock
forall a b. (a -> b) -> a -> b
$ () -> IO Lock
forall a. a -> IO (MVar a)
newMVar ()
{-# NOINLINE emptyLock #-}
initialize :: Int -> IO Manager
initialize :: Int -> IO Manager
initialize = Manager -> IO Manager
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Manager -> IO Manager) -> (Int -> Manager) -> Int -> IO Manager
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Manager
Manager (Int -> Manager) -> (Int -> Int) -> Int -> Manager
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0
stopManager :: Manager -> IO ()
stopManager :: Manager -> TimeoutAction
stopManager Manager
_ = () -> TimeoutAction
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
{-# DEPRECATED stopManager "This function does nothing since version 0.3.0" #-}
killManager :: Manager -> IO ()
killManager :: Manager -> TimeoutAction
killManager Manager
_ = () -> TimeoutAction
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
{-# DEPRECATED killManager "This function does nothing since version 0.3.0" #-}
withHandle :: Manager -> TimeoutAction -> (Handle -> IO a) -> IO a
withHandle :: forall a. Manager -> TimeoutAction -> (Handle -> IO a) -> IO a
withHandle Manager
mgr TimeoutAction
onTimeout Handle -> IO a
action
| Manager -> Bool
isNoManager Manager
mgr = Handle -> IO a
action Handle
emptyHandle
| Bool
otherwise = IO Handle -> (Handle -> TimeoutAction) -> (Handle -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
E.bracket (Manager -> TimeoutAction -> IO Handle
register Manager
mgr TimeoutAction
onTimeout) Handle -> TimeoutAction
cancel Handle -> IO a
action
withHandleKillThread :: Manager -> TimeoutAction -> (Handle -> IO ()) -> IO ()
withHandleKillThread :: Manager
-> TimeoutAction -> (Handle -> TimeoutAction) -> TimeoutAction
withHandleKillThread Manager
mgr TimeoutAction
onTimeout Handle -> TimeoutAction
action
| Manager -> Bool
isNoManager Manager
mgr = Handle -> TimeoutAction
action Handle
emptyHandle
| Bool
otherwise =
(TimeoutThread -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
E.handle TimeoutThread -> TimeoutAction
forall {f :: * -> *}. Applicative f => TimeoutThread -> f ()
ignore (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ IO Handle
-> (Handle -> TimeoutAction)
-> (Handle -> TimeoutAction)
-> TimeoutAction
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
E.bracket (Manager -> TimeoutAction -> IO Handle
registerKillThread Manager
mgr TimeoutAction
onTimeout) Handle -> TimeoutAction
cancel Handle -> TimeoutAction
action
where
ignore :: TimeoutThread -> f ()
ignore TimeoutThread
TimeoutThread = () -> f ()
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
register :: Manager -> TimeoutAction -> IO Handle
register :: Manager -> TimeoutAction -> IO Handle
register mgr :: Manager
mgr@(Manager Int
timeout) TimeoutAction
onTimeout
| Manager -> Bool
isNoManager Manager
mgr = Handle -> IO Handle
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Handle
emptyHandle
| Bool
otherwise = do
TimerManager
sysmgr <- IO TimerManager
getTimerManager
IORef HandleState
stateRef <- HandleState -> IO (IORef HandleState)
forall a. a -> IO (IORef a)
I.newIORef HandleState
Stopped
Lock
lock <- IO Lock
newLock
IORef Word64
lastRenewedRef <- Word64 -> IO (IORef Word64)
forall a. a -> IO (IORef a)
I.newIORef (Word64 -> IO (IORef Word64)) -> IO Word64 -> IO (IORef Word64)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO Word64
getMonotonicTimeNSec
let h :: Handle
h =
Handle
{ handleTimeout :: Int
handleTimeout = Int
timeout
, handleAction :: TimeoutAction
handleAction = TimeoutAction
onTimeout
, handleTimerManager :: TimerManager
handleTimerManager = TimerManager
sysmgr
, handleState :: IORef HandleState
handleState = IORef HandleState
stateRef
, handleLastRenewed :: IORef Word64
handleLastRenewed = IORef Word64
lastRenewedRef
, handleMinRenewGap :: Word64
handleMinRenewGap = Int -> Word64
minRenewGap Int
timeout
, handleLock :: Lock
handleLock = Lock
lock
}
Lock -> TimeoutAction -> TimeoutAction
forall a. Lock -> IO a -> IO a
withLock Lock
lock (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ do
TimeoutKey
key <- Handle -> Int -> IO TimeoutKey
registerAdjustedTimeout Handle
h Int
timeout
Word64
now <- IO Word64
getMonotonicTimeNSec
IORef Word64 -> Word64 -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.writeIORef IORef Word64
lastRenewedRef Word64
now
IORef HandleState -> HandleState -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.writeIORef IORef HandleState
stateRef (HandleState -> TimeoutAction) -> HandleState -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ TimeoutKey -> HandleState
Active TimeoutKey
key
Handle -> IO Handle
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Handle
h
registerAdjustedTimeout :: Handle -> Int -> IO EV.TimeoutKey
registerAdjustedTimeout :: Handle -> Int -> IO TimeoutKey
registerAdjustedTimeout h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} Int
timeout = do
IORef TimeoutKey
originalKeyRef <-
TimeoutKey -> IO (IORef TimeoutKey)
forall a. a -> IO (IORef a)
I.newIORef (TimeoutKey -> IO (IORef TimeoutKey))
-> TimeoutKey -> IO (IORef TimeoutKey)
forall a b. (a -> b) -> a -> b
$
[Char] -> TimeoutKey
forall a. HasCallStack => [Char] -> a
error [Char]
"System.TimeManager.registerAdjustedTimeout: originalKeyRef not filled"
TimeoutKey
key <-
TimerManager -> Int -> TimeoutAction -> IO TimeoutKey
EV.registerTimeout TimerManager
handleTimerManager Int
timeout (TimeoutAction -> IO TimeoutKey) -> TimeoutAction -> IO TimeoutKey
forall a b. (a -> b) -> a -> b
$
IORef TimeoutKey -> Handle -> TimeoutAction
adjustOnTimeout IORef TimeoutKey
originalKeyRef Handle
h
IORef TimeoutKey -> TimeoutKey -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.writeIORef IORef TimeoutKey
originalKeyRef TimeoutKey
key
TimeoutKey -> IO TimeoutKey
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TimeoutKey
key
adjustOnTimeout :: I.IORef EV.TimeoutKey -> Handle -> TimeoutAction
adjustOnTimeout :: IORef TimeoutKey -> Handle -> TimeoutAction
adjustOnTimeout IORef TimeoutKey
originalKeyRef h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} = do
let writeState :: HandleState -> TimeoutAction
writeState = IORef HandleState -> HandleState -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef HandleState
handleState
Bool
shouldRun <- Lock -> IO Bool -> IO Bool
forall a. Lock -> IO a -> IO a
withLock Lock
handleLock (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
HandleState
st <- IORef HandleState -> IO HandleState
forall a. IORef a -> IO a
I.readIORef IORef HandleState
handleState
case HandleState
st of
Active TimeoutKey
key -> do
TimeoutKey -> IO Bool -> IO Bool
ifSameKey TimeoutKey
key (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
Word64
lastRenewed <- IORef Word64 -> IO Word64
forall a. IORef a -> IO a
I.readIORef IORef Word64
handleLastRenewed
Word64
now <- IO Word64
getMonotonicTimeNSec
let diff :: Int
diff = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ (Word64
now Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
lastRenewed) Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`div` Word64
1_000
if Int
diff Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
handleTimeout
then do
HandleState -> TimeoutAction
writeState HandleState
Terminated
Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
else do
let remainingTimeout :: Int
remainingTimeout = Int
handleTimeout Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
diff
TimeoutKey
k <- Handle -> Int -> IO TimeoutKey
registerAdjustedTimeout Handle
h Int
remainingTimeout
HandleState -> TimeoutAction
writeState (HandleState -> TimeoutAction) -> HandleState -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ TimeoutKey -> HandleState
Active TimeoutKey
k
Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
Paused TimeoutKey
key ->
TimeoutKey -> IO Bool -> IO Bool
ifSameKey TimeoutKey
key (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
HandleState -> TimeoutAction
writeState HandleState
Stopped
Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
HandleState
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
Bool -> TimeoutAction -> TimeoutAction
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
shouldRun TimeoutAction
handleAction
where
ifSameKey :: TimeoutKey -> IO Bool -> IO Bool
ifSameKey TimeoutKey
key IO Bool
f = do
TimeoutKey
originalKey <- IORef TimeoutKey -> IO TimeoutKey
forall a. IORef a -> IO a
I.readIORef IORef TimeoutKey
originalKeyRef
if TimeoutKey
key TimeoutKey -> TimeoutKey -> Bool
forall a. Eq a => a -> a -> Bool
== TimeoutKey
originalKey
then IO Bool
f
else Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
minRenewGap :: Int -> Word64
minRenewGap :: Int -> Word64
minRenewGap Int
timeout =
Word64 -> Word64 -> Word64
forall a. Ord a => a -> a -> a
min Word64
maxRenewDebounce (Int -> Word64
microToNano Int
timeout Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
2)
where
microToNano :: Int -> Word64
microToNano = (Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
1_000) (Word64 -> Word64) -> (Int -> Word64) -> Int -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral
maxRenewDebounce :: Word64
maxRenewDebounce :: Word64
maxRenewDebounce = Word64
1_000_000_000
whenRenew :: Handle -> IO () -> IO ()
whenRenew :: Handle -> TimeoutAction -> TimeoutAction
whenRenew Handle
h TimeoutAction
f = do
Word64
now <- IO Word64
getMonotonicTimeNSec
Word64
lastRenewed <- IORef Word64 -> IO Word64
forall a. IORef a -> IO a
I.readIORef (IORef Word64 -> IO Word64) -> IORef Word64 -> IO Word64
forall a b. (a -> b) -> a -> b
$ Handle -> IORef Word64
handleLastRenewed Handle
h
Bool -> TimeoutAction -> TimeoutAction
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word64
now Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
lastRenewed Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Handle -> Word64
handleMinRenewGap Handle
h) TimeoutAction
f
cancel :: Handle -> IO ()
cancel :: Handle -> TimeoutAction
cancel h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} =
Handle -> TimeoutAction -> TimeoutAction
withNonEmptyHandle Handle
h (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
Lock -> TimeoutAction -> TimeoutAction
forall a. Lock -> IO a -> IO a
withLock Lock
handleLock (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ do
Handle -> (TimeoutKey -> TimeoutAction) -> TimeoutAction
withTimeoutKey Handle
h ((TimeoutKey -> TimeoutAction) -> TimeoutAction)
-> (TimeoutKey -> TimeoutAction) -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ TimerManager -> TimeoutKey -> TimeoutAction
EV.unregisterTimeout TimerManager
handleTimerManager
IORef HandleState -> HandleState -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef HandleState
handleState HandleState
Terminated
tickle :: Handle -> IO ()
tickle :: Handle -> TimeoutAction
tickle h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} =
Handle -> TimeoutAction -> TimeoutAction
withNonEmptyHandle Handle
h (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
Handle -> TimeoutAction -> TimeoutAction
whenRenew Handle
h (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
Handle -> (TimeoutKey -> TimeoutAction) -> TimeoutAction
withActiveTimeoutKey Handle
h ((TimeoutKey -> TimeoutAction) -> TimeoutAction)
-> (TimeoutKey -> TimeoutAction) -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ \TimeoutKey
key -> do
TimeoutKey -> TimeoutAction
updateTheTimeout TimeoutKey
key
Word64
now <- IO Word64
getMonotonicTimeNSec
IORef Word64 -> Word64 -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef Word64
handleLastRenewed Word64
now
where
updateTheTimeout :: TimeoutKey -> TimeoutAction
updateTheTimeout TimeoutKey
key =
TimerManager -> TimeoutKey -> Int -> TimeoutAction
EV.updateTimeout TimerManager
handleTimerManager TimeoutKey
key Int
handleTimeout
pause :: Handle -> IO ()
pause :: Handle -> TimeoutAction
pause h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} =
Handle -> TimeoutAction -> TimeoutAction
withNonEmptyHandle Handle
h (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
Lock -> TimeoutAction -> TimeoutAction
forall a. Lock -> IO a -> IO a
withLock Lock
handleLock (TimeoutAction -> TimeoutAction)
-> ((TimeoutKey -> TimeoutAction) -> TimeoutAction)
-> (TimeoutKey -> TimeoutAction)
-> TimeoutAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> (TimeoutKey -> TimeoutAction) -> TimeoutAction
withActiveTimeoutKey Handle
h ((TimeoutKey -> TimeoutAction) -> TimeoutAction)
-> (TimeoutKey -> TimeoutAction) -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
IORef HandleState -> HandleState -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef HandleState
handleState (HandleState -> TimeoutAction)
-> (TimeoutKey -> HandleState) -> TimeoutKey -> TimeoutAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeoutKey -> HandleState
Paused
resume :: Handle -> IO ()
resume :: Handle -> TimeoutAction
resume h :: Handle
h@Handle{Int
TimeoutAction
Word64
Lock
IORef Word64
IORef HandleState
TimerManager
handleTimeout :: Handle -> Int
handleAction :: Handle -> TimeoutAction
handleTimerManager :: Handle -> TimerManager
handleState :: Handle -> IORef HandleState
handleLastRenewed :: Handle -> IORef Word64
handleMinRenewGap :: Handle -> Word64
handleLock :: Handle -> Lock
handleTimeout :: Int
handleAction :: TimeoutAction
handleTimerManager :: TimerManager
handleLock :: Lock
handleState :: IORef HandleState
handleLastRenewed :: IORef Word64
handleMinRenewGap :: Word64
..} =
Handle -> TimeoutAction -> TimeoutAction
withNonEmptyHandle Handle
h (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$
(TimeoutKey -> TimeoutAction) -> TimeoutAction -> TimeoutAction
checkStateWith (\TimeoutKey
_ -> TimeoutAction
onPausedOrStopped) TimeoutAction
onPausedOrStopped
where
onPausedOrStopped :: TimeoutAction
onPausedOrStopped =
Lock -> TimeoutAction -> TimeoutAction
forall a. Lock -> IO a -> IO a
withLock Lock
handleLock (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ (TimeoutKey -> TimeoutAction) -> TimeoutAction -> TimeoutAction
checkStateWith TimeoutKey -> TimeoutAction
pausedF TimeoutAction
stoppedF
checkStateWith :: (TimeoutKey -> TimeoutAction) -> TimeoutAction -> TimeoutAction
checkStateWith TimeoutKey -> TimeoutAction
onPaused TimeoutAction
onStopped = do
HandleState
state <- IORef HandleState -> IO HandleState
forall a. IORef a -> IO a
I.readIORef IORef HandleState
handleState
case HandleState
state of
Active{} -> Handle -> TimeoutAction
tickle Handle
h
HandleState
Terminated -> () -> TimeoutAction
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Paused TimeoutKey
k -> TimeoutKey -> TimeoutAction
onPaused TimeoutKey
k
HandleState
Stopped -> TimeoutAction
onStopped
pausedF :: TimeoutKey -> TimeoutAction
pausedF TimeoutKey
k = do
TimeoutKey -> TimeoutAction
activateTimeout TimeoutKey
k
Handle -> TimeoutAction
tickle Handle
h
stoppedF :: TimeoutAction
stoppedF = do
TimeoutKey
key <- Handle -> Int -> IO TimeoutKey
registerAdjustedTimeout Handle
h Int
handleTimeout
Word64
now <- IO Word64
getMonotonicTimeNSec
IORef Word64 -> Word64 -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef Word64
handleLastRenewed Word64
now
TimeoutKey -> TimeoutAction
activateTimeout TimeoutKey
key
activateTimeout :: TimeoutKey -> TimeoutAction
activateTimeout =
IORef HandleState -> HandleState -> TimeoutAction
forall a. IORef a -> a -> TimeoutAction
I.atomicWriteIORef IORef HandleState
handleState (HandleState -> TimeoutAction)
-> (TimeoutKey -> HandleState) -> TimeoutKey -> TimeoutAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeoutKey -> HandleState
Active
data TimeoutThread = TimeoutThread
instance E.Exception TimeoutThread where
toException :: TimeoutThread -> SomeException
toException = TimeoutThread -> SomeException
forall e. Exception e => e -> SomeException
E.asyncExceptionToException
fromException :: SomeException -> Maybe TimeoutThread
fromException = SomeException -> Maybe TimeoutThread
forall e. Exception e => SomeException -> Maybe e
E.asyncExceptionFromException
instance Show TimeoutThread where
show :: TimeoutThread -> [Char]
show TimeoutThread
TimeoutThread = [Char]
"Thread killed by timeout manager"
registerKillThread :: Manager -> TimeoutAction -> IO Handle
registerKillThread :: Manager -> TimeoutAction -> IO Handle
registerKillThread Manager
m TimeoutAction
onTimeout = do
Weak ThreadId
wtid <- IO ThreadId
myThreadId IO ThreadId
-> (ThreadId -> IO (Weak ThreadId)) -> IO (Weak ThreadId)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ThreadId -> IO (Weak ThreadId)
mkWeakThreadId
Manager -> TimeoutAction -> IO Handle
register Manager
m (TimeoutAction -> IO Handle) -> TimeoutAction -> IO Handle
forall a b. (a -> b) -> a -> b
$
TimeoutAction
onTimeout TimeoutAction -> TimeoutAction -> TimeoutAction
forall a b. IO a -> IO b -> IO a
`E.finally` do
Maybe ThreadId
mtid <- Weak ThreadId -> IO (Maybe ThreadId)
forall v. Weak v -> IO (Maybe v)
deRefWeak Weak ThreadId
wtid
case Maybe ThreadId
mtid of
Maybe ThreadId
Nothing -> () -> TimeoutAction
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just ThreadId
tid' -> IO ThreadId -> TimeoutAction
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> TimeoutAction)
-> (TimeoutAction -> IO ThreadId) -> TimeoutAction -> TimeoutAction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeoutAction -> IO ThreadId
forkIO (TimeoutAction -> TimeoutAction) -> TimeoutAction -> TimeoutAction
forall a b. (a -> b) -> a -> b
$ ThreadId -> TimeoutThread -> TimeoutAction
forall e. Exception e => ThreadId -> e -> TimeoutAction
E.throwTo ThreadId
tid' TimeoutThread
TimeoutThread
withManager
:: Int
-> (Manager -> IO a)
-> IO a
withManager :: forall a. Int -> (Manager -> IO a) -> IO a
withManager Int
timeout Manager -> IO a
f = Int -> IO Manager
initialize Int
timeout IO Manager -> (Manager -> IO a) -> IO a
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Manager -> IO a
f
withManager'
:: Int
-> (Manager -> IO a)
-> IO a
withManager' :: forall a. Int -> (Manager -> IO a) -> IO a
withManager' = Int -> (Manager -> IO a) -> IO a
forall a. Int -> (Manager -> IO a) -> IO a
withManager
{-# DEPRECATED withManager' "This function is the same as 'withManager' since version 0.3.0" #-}