{-# OPTIONS_GHC -Wno-missing-signatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE CPP #-}
module Debug.Breakpoint.TimerManager
( suspendTimeouts
) where
#if defined(mingw32_HOST_OS)
suspendTimeouts :: IO a -> IO a
suspendTimeouts = id
#else
import Control.Concurrent(rtsSupportsBoundThreads)
import Control.Monad (when)
import Data.Foldable (foldl')
import Data.IORef
import Data.Word (Word64)
import qualified GHC.Clock as Clock
import GHC.Event
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import System.IO.Unsafe
psqToList :: IntPSQ v -> [Elem v]
psqToList =
$(pure $ VarE $
Name (OccName "toList")
(NameG VarName (PkgName "base") (ModName "GHC.Event.PSQ"))
)
psqAdjust :: (Prio -> Prio) -> Key -> PSQ a -> PSQ a
psqAdjust =
$(pure $ VarE $
Name (OccName "adjust")
(NameG VarName (PkgName "base") (ModName "GHC.Event.PSQ"))
)
psqKey :: Elem a -> Key
psqKey =
$(pure $ VarE $
Name (OccName "key")
#if MIN_VERSION_ghc(9,8,0)
(NameG (FldName "E") (PkgName "base") (ModName "GHC.Event.PSQ"))
#else
(NameG VarName (PkgName "base") (ModName "GHC.Event.PSQ"))
#endif
)
emTimeouts :: TimerManager -> IORef TimeoutQueue
emTimeouts =
$(pure $ VarE $
Name (OccName "emTimeouts")
#if MIN_VERSION_ghc(9,8,0)
(NameG (FldName "TimerManager") (PkgName "base") (ModName "GHC.Event.TimerManager"))
#else
(NameG VarName (PkgName "base") (ModName "GHC.Event.TimerManager"))
#endif
)
wakeManager :: TimerManager -> IO ()
wakeManager :: TimerManager -> IO ()
wakeManager =
$(pure $ VarE $
Name (OccName "wakeManager")
(NameG VarName (PkgName "base") (ModName "GHC.Event.TimerManager"))
)
editTimeouts :: TimerManager -> (TimeoutQueue -> TimeoutQueue) -> IO ()
editTimeouts TimerManager
mgr TimeoutQueue -> TimeoutQueue
g = do
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (TimerManager -> IORef TimeoutQueue
emTimeouts TimerManager
mgr) TimeoutQueue -> (TimeoutQueue, ())
f
TimerManager -> IO ()
wakeManager TimerManager
mgr
where
f :: TimeoutQueue -> (TimeoutQueue, ())
f TimeoutQueue
q = (TimeoutQueue -> TimeoutQueue
g TimeoutQueue
q, ())
modifyTimeouts :: (Word64 -> Word64) -> IO ()
modifyTimeouts :: (Prio -> Prio) -> IO ()
modifyTimeouts Prio -> Prio
f =
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
rtsSupportsBoundThreads forall a b. (a -> b) -> a -> b
$ do
TimerManager
mgr <- IO TimerManager
getSystemTimerManager
TimerManager -> (TimeoutQueue -> TimeoutQueue) -> IO ()
editTimeouts TimerManager
mgr forall a b. (a -> b) -> a -> b
$ \TimeoutQueue
pq ->
let els :: [Elem (IO ())]
els = forall v. IntPSQ v -> [Elem v]
psqToList TimeoutQueue
pq
upd :: PSQ a -> Key -> PSQ a
upd PSQ a
pq' Key
k =
forall a. (Prio -> Prio) -> Key -> PSQ a -> PSQ a
psqAdjust Prio -> Prio
f Key
k PSQ a
pq'
in forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall {a}. PSQ a -> Key -> PSQ a
upd TimeoutQueue
pq (forall a. Elem a -> Key
psqKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Elem (IO ())]
els)
suspendTimeouts :: IO a -> IO a
suspendTimeouts :: forall a. IO a -> IO a
suspendTimeouts IO a
action = do
Bool
alreadySuspended <- forall a. IORef a -> IO a
readIORef IORef Bool
timeoutsSuspended
if Bool
alreadySuspended Bool -> Bool -> Bool
|| Bool -> Bool
not Bool
rtsSupportsBoundThreads
then IO a
action
else do
forall a. IORef a -> a -> IO ()
writeIORef IORef Bool
timeoutsSuspended Bool
True
let oneYear :: Prio
oneYear = Prio
1000 forall a. Num a => a -> a -> a
* Prio
1000000 forall a. Num a => a -> a -> a
* Prio
60 forall a. Num a => a -> a -> a
* Prio
60 forall a. Num a => a -> a -> a
* Prio
24 forall a. Num a => a -> a -> a
* Prio
365
(Prio -> Prio) -> IO ()
modifyTimeouts (forall a. Num a => a -> a -> a
+ Prio
oneYear)
Prio
before <- IO Prio
Clock.getMonotonicTimeNSec
a
r <- IO a
action
Prio
after <- IO Prio
Clock.getMonotonicTimeNSec
let elapsed :: Prio
elapsed = Prio
after forall a. Num a => a -> a -> a
- Prio
before
(Prio -> Prio) -> IO ()
modifyTimeouts (forall a. Num a => a -> a -> a
subtract forall a b. (a -> b) -> a -> b
$ Prio
oneYear forall a. Num a => a -> a -> a
- Prio
elapsed)
forall a. IORef a -> a -> IO ()
writeIORef IORef Bool
timeoutsSuspended Bool
False
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
r
timeoutsSuspended :: IORef Bool
timeoutsSuspended :: IORef Bool
timeoutsSuspended = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef Bool
False
{-# NOINLINE timeoutsSuspended #-}
#endif