{-# LANGUAGE Trustworthy #-}{-# LANGUAGE BangPatterns
 , CPP
 , ExistentialQuantification
 , NoImplicitPrelude
 , TypeSynonymInstances
 , FlexibleInstances
 #-}moduleGHC.Event.TimerManager(-- * TypesTimerManager -- * Creation,new ,newWith ,newDefaultBackend ,emControl -- * Running,finished ,loop ,step ,shutdown ,cleanup ,wakeManager -- * Registering interest in timeout events,TimeoutCallback ,TimeoutKey ,registerTimeout ,updateTimeout ,unregisterTimeout )where
#include "EventConfig.h"
-------------------------------------------------------------------------- ImportsimportControl.Exception (finally )importData.Foldable (sequence_ )importData.IORef (IORef ,atomicModifyIORef' ,mkWeakIORef ,newIORef ,readIORef ,writeIORef )importGHC.Base importGHC.Clock (getMonotonicTimeNSec )importGHC.Conc.Signal (runHandlers )importGHC.Enum (maxBound )importGHC.Num (Num (..))importGHC.Real (quot ,fromIntegral )importGHC.Show (Show (..))importGHC.Event.Control importGHC.Event.Internal (Backend ,Event ,evtRead ,Timeout (..))importGHC.Event.Unique (Unique ,UniqueSource ,newSource ,newUnique )importSystem.Posix.Types (Fd )importqualifiedGHC.Event.Internal asIimportqualifiedGHC.Event.PSQ asQ
#if defined(HAVE_POLL)
importqualifiedGHC.Event.Poll asPoll
#else
# error not implemented for this operating system
#endif
-------------------------------------------------------------------------- Types-- | A timeout registration cookie.newtypeTimeoutKey =TK Unique derivingEq-- ^ @since 4.7.0.0-- | Callback invoked on timeout events.typeTimeoutCallback =IO()dataState =Created |Running |Dying |Finished deriving(Eq-- ^ @since 4.7.0.0,Show -- ^ @since 4.7.0.0)-- | A priority search queue, with timeouts as priorities.typeTimeoutQueue =Q.PSQ TimeoutCallback -- | An edit to apply to a 'TimeoutQueue'.typeTimeoutEdit =TimeoutQueue ->TimeoutQueue -- | The event manager state.dataTimerManager =TimerManager {TimerManager -> Backend
emBackend ::!Backend ,TimerManager -> IORef TimeoutQueue
emTimeouts ::{-# UNPACK#-}!(IORef TimeoutQueue ),TimerManager -> IORef State
emState ::{-# UNPACK#-}!(IORef State ),TimerManager -> UniqueSource
emUniqueSource ::{-# UNPACK#-}!UniqueSource ,TimerManager -> Control
emControl ::{-# UNPACK#-}!Control }-------------------------------------------------------------------------- CreationhandleControlEvent ::TimerManager ->Fd ->Event ->IO()handleControlEvent :: TimerManager -> Fd -> Event -> IO ()
handleControlEvent mgr :: TimerManager
mgr fd :: Fd
fd _evt :: Event
_evt =doControlMessage
msg <-Control -> Fd -> IO ControlMessage
readControlMessage (TimerManager -> Control
emControl TimerManager
mgr )Fd
fd caseControlMessage
msg ofCMsgWakeup ->() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()CMsgDie ->IORef State -> State -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (TimerManager -> IORef State
emState TimerManager
mgr )State
Finished CMsgSignal fp :: ForeignPtr Word8
fp s :: Signal
s ->ForeignPtr Word8 -> Signal -> IO ()
runHandlers ForeignPtr Word8
fp Signal
s newDefaultBackend ::IOBackend 
#if defined(HAVE_POLL)
newDefaultBackend :: IO Backend
newDefaultBackend =IO Backend
Poll.new 
#else
newDefaultBackend=errorWithoutStackTrace"no back end for this platform"
#endif
-- | Create a new event manager.new ::IOTimerManager new :: IO TimerManager
new =Backend -> IO TimerManager
newWith (Backend -> IO TimerManager) -> IO Backend -> IO TimerManager
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO Backend
newDefaultBackend newWith ::Backend ->IOTimerManager newWith :: Backend -> IO TimerManager
newWith be :: Backend
be =doIORef TimeoutQueue
timeouts <-TimeoutQueue -> IO (IORef TimeoutQueue)
forall a. a -> IO (IORef a)
newIORef TimeoutQueue
forall v. IntPSQ v
Q.empty Control
ctrl <-Bool -> IO Control
newControl Bool
TrueIORef State
state <-State -> IO (IORef State)
forall a. a -> IO (IORef a)
newIORef State
Created UniqueSource
us <-IO UniqueSource
newSource Weak (IORef State)
_<-IORef State -> IO () -> IO (Weak (IORef State))
forall a. IORef a -> IO () -> IO (Weak (IORef a))
mkWeakIORef IORef State
state (IO () -> IO (Weak (IORef State)))
-> IO () -> IO (Weak (IORef State))
forall a b. (a -> b) -> a -> b
$ doState
st <-IORef State -> (State -> (State, State)) -> IO State
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef State
state ((State -> (State, State)) -> IO State)
-> (State -> (State, State)) -> IO State
forall a b. (a -> b) -> a -> b
$ \s :: State
s ->(State
Finished ,State
s )Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (State
st State -> State -> Bool
forall a. Eq a => a -> a -> Bool
/=State
Finished )(IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ doBackend -> IO ()
I.delete Backend
be Control -> IO ()
closeControl Control
ctrl letmgr :: TimerManager
mgr =$WTimerManager :: Backend
-> IORef TimeoutQueue
-> IORef State
-> UniqueSource
-> Control
-> TimerManager
TimerManager {emBackend :: Backend
emBackend =Backend
be ,emTimeouts :: IORef TimeoutQueue
emTimeouts =IORef TimeoutQueue
timeouts ,emState :: IORef State
emState =IORef State
state ,emUniqueSource :: UniqueSource
emUniqueSource =UniqueSource
us ,emControl :: Control
emControl =Control
ctrl }Bool
_<-Backend -> Fd -> Event -> Event -> IO Bool
I.modifyFd Backend
be (Control -> Fd
controlReadFd Control
ctrl )Event
forall a. Monoid a => a
mempty Event
evtRead Bool
_<-Backend -> Fd -> Event -> Event -> IO Bool
I.modifyFd Backend
be (Control -> Fd
wakeupReadFd Control
ctrl )Event
forall a. Monoid a => a
mempty Event
evtRead TimerManager -> IO TimerManager
forall (m :: * -> *) a. Monad m => a -> m a
return TimerManager
mgr -- | Asynchronously shuts down the event manager, if running.shutdown ::TimerManager ->IO()shutdown :: TimerManager -> IO ()
shutdown mgr :: TimerManager
mgr =doState
state <-IORef State -> (State -> (State, State)) -> IO State
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (TimerManager -> IORef State
emState TimerManager
mgr )((State -> (State, State)) -> IO State)
-> (State -> (State, State)) -> IO State
forall a b. (a -> b) -> a -> b
$ \s :: State
s ->(State
Dying ,State
s )Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (State
state State -> State -> Bool
forall a. Eq a => a -> a -> Bool
==State
Running )(IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Control -> IO ()
sendDie (TimerManager -> Control
emControl TimerManager
mgr )finished ::TimerManager ->IOBoolfinished :: TimerManager -> IO Bool
finished mgr :: TimerManager
mgr =(State -> State -> Bool
forall a. Eq a => a -> a -> Bool
==State
Finished )(State -> Bool) -> IO State -> IO Bool
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` IORef State -> IO State
forall a. IORef a -> IO a
readIORef (TimerManager -> IORef State
emState TimerManager
mgr )cleanup ::TimerManager ->IO()cleanup :: TimerManager -> IO ()
cleanup mgr :: TimerManager
mgr =doIORef State -> State -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (TimerManager -> IORef State
emState TimerManager
mgr )State
Finished Backend -> IO ()
I.delete (TimerManager -> Backend
emBackend TimerManager
mgr )Control -> IO ()
closeControl (TimerManager -> Control
emControl TimerManager
mgr )-------------------------------------------------------------------------- Event loop-- | Start handling events. This function loops until told to stop,-- using 'shutdown'.---- /Note/: This loop can only be run once per 'TimerManager', as it-- closes all of its control resources when it finishes.loop ::TimerManager ->IO()loop :: TimerManager -> IO ()
loop mgr :: TimerManager
mgr =doState
state <-IORef State -> (State -> (State, State)) -> IO State
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (TimerManager -> IORef State
emState TimerManager
mgr )((State -> (State, State)) -> IO State)
-> (State -> (State, State)) -> IO State
forall a b. (a -> b) -> a -> b
$ \s :: State
s ->caseState
s ofCreated ->(State
Running ,State
s )_->(State
s ,State
s )caseState
state ofCreated ->IO ()
go IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`finally` TimerManager -> IO ()
cleanup TimerManager
mgr Dying ->TimerManager -> IO ()
cleanup TimerManager
mgr _->doTimerManager -> IO ()
cleanup TimerManager
mgr String -> IO ()
forall a. String -> a
errorWithoutStackTrace (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ "GHC.Event.Manager.loop: state is already "String -> ShowS
forall a. [a] -> [a] -> [a]
++ State -> String
forall a. Show a => a -> String
show State
state wherego :: IO ()
go =doBool
running <-TimerManager -> IO Bool
step TimerManager
mgr Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
running IO ()
go step ::TimerManager ->IOBoolstep :: TimerManager -> IO Bool
step mgr :: TimerManager
mgr =doTimeout
timeout <-IO Timeout
mkTimeout Int
_<-Backend -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int
I.poll (TimerManager -> Backend
emBackend TimerManager
mgr )(Timeout -> Maybe Timeout
forall a. a -> Maybe a
Just Timeout
timeout )(TimerManager -> Fd -> Event -> IO ()
handleControlEvent TimerManager
mgr )State
state <-IORef State -> IO State
forall a. IORef a -> IO a
readIORef (TimerManager -> IORef State
emState TimerManager
mgr )State
state State -> IO Bool -> IO Bool
forall a b. a -> b -> b
`seq`Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (State
state State -> State -> Bool
forall a. Eq a => a -> a -> Bool
==State
Running )where-- | Call all expired timer callbacks and return the time to the-- next timeout.mkTimeout ::IOTimeout mkTimeout :: IO Timeout
mkTimeout =doWord64
now <-IO Word64
getMonotonicTimeNSec (expired :: [Elem (IO ())]
expired ,timeout :: Timeout
timeout )<-IORef TimeoutQueue
-> (TimeoutQueue -> (TimeoutQueue, ([Elem (IO ())], Timeout)))
-> IO ([Elem (IO ())], Timeout)
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (TimerManager -> IORef TimeoutQueue
emTimeouts TimerManager
mgr )((TimeoutQueue -> (TimeoutQueue, ([Elem (IO ())], Timeout)))
 -> IO ([Elem (IO ())], Timeout))
-> (TimeoutQueue -> (TimeoutQueue, ([Elem (IO ())], Timeout)))
-> IO ([Elem (IO ())], Timeout)
forall a b. (a -> b) -> a -> b
$ \tq :: TimeoutQueue
tq ->let(expired :: [Elem (IO ())]
expired ,tq' :: TimeoutQueue
tq' )=Word64 -> TimeoutQueue -> ([Elem (IO ())], TimeoutQueue)
forall v. Word64 -> IntPSQ v -> ([Elem v], IntPSQ v)
Q.atMost Word64
now TimeoutQueue
tq timeout :: Timeout
timeout =caseTimeoutQueue -> Maybe (Elem (IO ()), TimeoutQueue)
forall v. IntPSQ v -> Maybe (Elem v, IntPSQ v)
Q.minView TimeoutQueue
tq' ofNothing ->Timeout
Forever Just (Q.E _t :: Word64
t _,_)->-- This value will always be positive since the call-- to 'atMost' above removed any timeouts <= 'now'lett' :: Word64
t' =Word64
t Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
now inWord64
t' Word64 -> Timeout -> Timeout
forall a b. a -> b -> b
`seq`Word64 -> Timeout
Timeout Word64
t' in(TimeoutQueue
tq' ,([Elem (IO ())]
expired ,Timeout
timeout ))[IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ ([IO ()] -> IO ()) -> [IO ()] -> IO ()
forall a b. (a -> b) -> a -> b
$ (Elem (IO ()) -> IO ()) -> [Elem (IO ())] -> [IO ()]
forall a b. (a -> b) -> [a] -> [b]
map Elem (IO ()) -> IO ()
forall a. Elem a -> a
Q.value [Elem (IO ())]
expired Timeout -> IO Timeout
forall (m :: * -> *) a. Monad m => a -> m a
return Timeout
timeout -- | Wake up the event manager.wakeManager ::TimerManager ->IO()wakeManager :: TimerManager -> IO ()
wakeManager mgr :: TimerManager
mgr =Control -> IO ()
sendWakeup (TimerManager -> Control
emControl TimerManager
mgr )-------------------------------------------------------------------------- Registering interest in timeout eventsexpirationTime ::Int->IOQ.Prio expirationTime :: Int -> IO Word64
expirationTime us :: Int
us =doWord64
now <-IO Word64
getMonotonicTimeNSec letexpTime :: Word64
expTime -- Currently we treat overflows by clamping to maxBound. If humanity-- still exists in 2500 CE we will ned to be a bit more careful here.-- See #15158.|(Word64
forall a. Bounded a => a
maxBound Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
now )Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`quot` 1000Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
us =Word64
forall a. Bounded a => a
maxBound |Bool
otherwise =Word64
now Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
ns wherens :: Word64
ns =1000Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
us Word64 -> IO Word64
forall (m :: * -> *) a. Monad m => a -> m a
return Word64
expTime -- | Register a timeout in the given number of microseconds. The-- returned 'TimeoutKey' can be used to later unregister or update the-- timeout. The timeout is automatically unregistered after the given-- time has passed.registerTimeout ::TimerManager ->Int->TimeoutCallback ->IOTimeoutKey registerTimeout :: TimerManager -> Int -> IO () -> IO TimeoutKey
registerTimeout mgr :: TimerManager
mgr us :: Int
us cb :: IO ()
cb =do!Unique
key <-UniqueSource -> IO Unique
newUnique (TimerManager -> UniqueSource
emUniqueSource TimerManager
mgr )ifInt
us Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=0thenIO ()
cb elsedoWord64
expTime <-Int -> IO Word64
expirationTime Int
us -- "unsafeInsertNew" is safe - the key must not exist in the PSQ. It-- doesn't because we just generated it from a unique supply.TimerManager -> TimeoutEdit -> IO ()
editTimeouts TimerManager
mgr (Unique -> Word64 -> IO () -> TimeoutEdit
forall v. Unique -> Word64 -> v -> IntPSQ v -> IntPSQ v
Q.unsafeInsertNew Unique
key Word64
expTime IO ()
cb )TimeoutKey -> IO TimeoutKey
forall (m :: * -> *) a. Monad m => a -> m a
return (TimeoutKey -> IO TimeoutKey) -> TimeoutKey -> IO TimeoutKey
forall a b. (a -> b) -> a -> b
$ Unique -> TimeoutKey
TK Unique
key -- | Unregister an active timeout.unregisterTimeout ::TimerManager ->TimeoutKey ->IO()unregisterTimeout :: TimerManager -> TimeoutKey -> IO ()
unregisterTimeout mgr :: TimerManager
mgr (TK key :: Unique
key )=doTimerManager -> TimeoutEdit -> IO ()
editTimeouts TimerManager
mgr (Unique -> TimeoutEdit
forall v. Unique -> IntPSQ v -> IntPSQ v
Q.delete Unique
key )-- | Update an active timeout to fire in the given number of-- microseconds.updateTimeout ::TimerManager ->TimeoutKey ->Int->IO()updateTimeout :: TimerManager -> TimeoutKey -> Int -> IO ()
updateTimeout mgr :: TimerManager
mgr (TK key :: Unique
key )us :: Int
us =doWord64
expTime <-Int -> IO Word64
expirationTime Int
us TimerManager -> TimeoutEdit -> IO ()
editTimeouts TimerManager
mgr ((Word64 -> Word64) -> Unique -> TimeoutEdit
forall a. (Word64 -> Word64) -> Unique -> PSQ a -> PSQ a
Q.adjust (Word64 -> Word64 -> Word64
forall a b. a -> b -> a
const Word64
expTime )Unique
key )editTimeouts ::TimerManager ->TimeoutEdit ->IO()editTimeouts :: TimerManager -> TimeoutEdit -> IO ()
editTimeouts mgr :: TimerManager
mgr g :: TimeoutEdit
g =doBool
wake <-IORef TimeoutQueue
-> (TimeoutQueue -> (TimeoutQueue, Bool)) -> IO Bool
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (TimerManager -> IORef TimeoutQueue
emTimeouts TimerManager
mgr )TimeoutQueue -> (TimeoutQueue, Bool)
f Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
wake (TimerManager -> IO ()
wakeManager TimerManager
mgr )wheref :: TimeoutQueue -> (TimeoutQueue, Bool)
f q :: TimeoutQueue
q =(TimeoutQueue
q' ,Bool
wake )whereq' :: TimeoutQueue
q' =TimeoutEdit
g TimeoutQueue
q wake :: Bool
wake =caseTimeoutQueue -> Maybe (Elem (IO ()), TimeoutQueue)
forall v. IntPSQ v -> Maybe (Elem v, IntPSQ v)
Q.minView TimeoutQueue
q ofNothing ->Bool
TrueJust (Q.E _t0 :: Word64
t0 _,_)->caseTimeoutQueue -> Maybe (Elem (IO ()), TimeoutQueue)
forall v. IntPSQ v -> Maybe (Elem v, IntPSQ v)
Q.minView TimeoutQueue
q' ofJust (Q.E _t1 :: Word64
t1 _,_)->-- don't wake the manager if the-- minimum element didn't change.Word64
t0 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/=Word64
t1 _->Bool
True

AltStyle によって変換されたページ (->オリジナル) /