summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Event
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/GHC/Event')
-rw-r--r--libraries/base/GHC/Event/Clock.hsc21
-rw-r--r--libraries/base/GHC/Event/Control.hs6
-rw-r--r--libraries/base/GHC/Event/EPoll.hsc7
-rw-r--r--libraries/base/GHC/Event/Internal.hs36
-rw-r--r--libraries/base/GHC/Event/KQueue.hsc69
-rw-r--r--libraries/base/GHC/Event/Manager.hs8
-rw-r--r--libraries/base/GHC/Event/PSQ.hs21
-rw-r--r--libraries/base/GHC/Event/Poll.hsc10
-rw-r--r--libraries/base/GHC/Event/Thread.hs8
-rw-r--r--libraries/base/GHC/Event/TimerManager.hs34
-rw-r--r--libraries/base/GHC/Event/Unique.hs5
11 files changed, 125 insertions, 100 deletions
diff --git a/libraries/base/GHC/Event/Clock.hsc b/libraries/base/GHC/Event/Clock.hsc
deleted file mode 100644
index 7f98a03cd2..0000000000
--- a/libraries/base/GHC/Event/Clock.hsc
+++ /dev/null
@@ -1,21 +0,0 @@
-{-# LANGUAGE Trustworthy #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module GHC.Event.Clock
- ( getMonotonicTime
- , getMonotonicTimeNSec
- ) where
-
-import GHC.Base
-import GHC.Real
-import Data.Word
-
--- | Return monotonic time in seconds, since some unspecified starting point
-getMonotonicTime :: IO Double
-getMonotonicTime = do w <- getMonotonicTimeNSec
- return (fromIntegral w / 1000000000)
-
--- | Return monotonic time in nanoseconds, since some unspecified starting point
-foreign import ccall unsafe "getMonotonicNSec"
- getMonotonicTimeNSec :: IO Word64
-
diff --git a/libraries/base/GHC/Event/Control.hs b/libraries/base/GHC/Event/Control.hs
index 9e3940ad19..779d60d5d7 100644
--- a/libraries/base/GHC/Event/Control.hs
+++ b/libraries/base/GHC/Event/Control.hs
@@ -57,7 +57,9 @@ data ControlMessage = CMsgWakeup
| CMsgDie
| CMsgSignal {-# UNPACK #-} !(ForeignPtr Word8)
{-# UNPACK #-} !Signal
- deriving (Eq, Show)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ )
-- | The structure used to tell the IO manager thread what to do.
data Control = W {
@@ -124,7 +126,7 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
-- file after it has been closed.
closeControl :: Control -> IO ()
closeControl w = do
- atomicModifyIORef (controlIsDead w) (\_ -> (True, ()))
+ _ <- atomicSwapIORef (controlIsDead w) True
_ <- c_close . fromIntegral . controlReadFd $ w
_ <- c_close . fromIntegral . controlWriteFd $ w
when (didRegisterWakeupFd w) $ c_setIOManagerWakeupFd (-1)
diff --git a/libraries/base/GHC/Event/EPoll.hsc b/libraries/base/GHC/Event/EPoll.hsc
index 32bfc3913b..14324bc43d 100644
--- a/libraries/base/GHC/Event/EPoll.hsc
+++ b/libraries/base/GHC/Event/EPoll.hsc
@@ -161,7 +161,12 @@ newtype ControlOp = ControlOp CInt
newtype EventType = EventType {
unEventType :: Word32
- } deriving (Show, Eq, Num, Bits, FiniteBits)
+ } deriving ( Show -- ^ @since 4.4.0.0
+ , Eq -- ^ @since 4.4.0.0
+ , Num -- ^ @since 4.4.0.0
+ , Bits -- ^ @since 4.4.0.0
+ , FiniteBits -- ^ @since 4.7.0.0
+ )
#{enum EventType, EventType
, epollIn = EPOLLIN
diff --git a/libraries/base/GHC/Event/Internal.hs b/libraries/base/GHC/Event/Internal.hs
index 9b8230c032..5778c6f3fe 100644
--- a/libraries/base/GHC/Event/Internal.hs
+++ b/libraries/base/GHC/Event/Internal.hs
@@ -36,10 +36,11 @@ import GHC.Base
import GHC.Word (Word64)
import GHC.Num (Num(..))
import GHC.Show (Show(..))
+import Data.Semigroup.Internal (stimesMonoid)
-- | An I\/O event.
newtype Event = Event Int
- deriving (Eq)
+ deriving Eq -- ^ @since 4.4.0.0
evtNothing :: Event
evtNothing = Event 0
@@ -63,7 +64,7 @@ evtClose = Event 4
eventIs :: Event -> Event -> Bool
eventIs (Event a) (Event b) = a .&. b /= 0
--- | @since 4.3.1.0
+-- | @since 4.4.0.0
instance Show Event where
show e = '[' : (intercalate "," . filter (not . null) $
[evtRead `so` "evtRead",
@@ -72,10 +73,14 @@ instance Show Event where
where ev `so` disp | e `eventIs` ev = disp
| otherwise = ""
--- | @since 4.3.1.0
+-- | @since 4.10.0.0
+instance Semigroup Event where
+ (<>) = evtCombine
+ stimes = stimesMonoid
+
+-- | @since 4.4.0.0
instance Monoid Event where
mempty = evtNothing
- mappend = evtCombine
mconcat = evtConcat
evtCombine :: Event -> Event -> Event
@@ -92,7 +97,9 @@ evtConcat = foldl' evtCombine evtNothing
data Lifetime = OneShot -- ^ the registration will be active for only one
-- event
| MultiShot -- ^ the registration will trigger multiple times
- deriving (Show, Eq)
+ deriving ( Show -- ^ @since 4.8.1.0
+ , Eq -- ^ @since 4.8.1.0
+ )
-- | The longer of two lifetimes.
elSupremum :: Lifetime -> Lifetime -> Lifetime
@@ -100,24 +107,33 @@ elSupremum OneShot OneShot = OneShot
elSupremum _ _ = MultiShot
{-# INLINE elSupremum #-}
+-- | @since 4.10.0.0
+instance Semigroup Lifetime where
+ (<>) = elSupremum
+ stimes = stimesMonoid
+
-- | @mappend@ takes the longer of two lifetimes.
--
-- @since 4.8.0.0
instance Monoid Lifetime where
mempty = OneShot
- mappend = elSupremum
-- | A pair of an event and lifetime
--
-- Here we encode the event in the bottom three bits and the lifetime
-- in the fourth bit.
newtype EventLifetime = EL Int
- deriving (Show, Eq)
+ deriving ( Show -- ^ @since 4.8.0.0
+ , Eq -- ^ @since 4.8.0.0
+ )
+
+-- | @since 4.11.0.0
+instance Semigroup EventLifetime where
+ EL a <> EL b = EL (a .|. b)
-- | @since 4.8.0.0
instance Monoid EventLifetime where
mempty = EL 0
- EL a `mappend` EL b = EL (a .|. b)
eventLifetime :: Event -> Lifetime -> EventLifetime
eventLifetime (Event e) l = EL (e .|. lifetimeBit l)
@@ -137,7 +153,7 @@ elEvent (EL x) = Event (x .&. 0x7)
-- | A type alias for timeouts, specified in nanoseconds.
data Timeout = Timeout {-# UNPACK #-} !Word64
| Forever
- deriving (Show)
+ deriving Show -- ^ @since 4.4.0.0
-- | Event notification backend.
data Backend = forall a. Backend {
@@ -200,7 +216,7 @@ delete :: Backend -> IO ()
delete (Backend bState _ _ _ bDelete) = bDelete bState
{-# INLINE delete #-}
--- | Throw an 'IOError' corresponding to the current value of
+-- | Throw an 'Prelude.IOError' corresponding to the current value of
-- 'getErrno' if the result value of the 'IO' action is -1 and
-- 'getErrno' is not 'eINTR'. If the result value is -1 and
-- 'getErrno' returns 'eINTR' 0 is returned. Otherwise the result
diff --git a/libraries/base/GHC/Event/KQueue.hsc b/libraries/base/GHC/Event/KQueue.hsc
index e9c8419ea7..49cf82db14 100644
--- a/libraries/base/GHC/Event/KQueue.hsc
+++ b/libraries/base/GHC/Event/KQueue.hsc
@@ -28,11 +28,13 @@ available = False
import Data.Bits (Bits(..), FiniteBits(..))
import Data.Int
+import Data.Maybe ( catMaybes )
import Data.Word (Word16, Word32)
import Foreign.C.Error (throwErrnoIfMinus1, eINTR, eINVAL,
eNOTSUP, getErrno, throwErrno)
import Foreign.C.Types
import Foreign.Marshal.Alloc (alloca)
+import Foreign.Marshal.Array (withArrayLen)
import Foreign.Ptr (Ptr, nullPtr)
import Foreign.Storable (Storable(..))
import GHC.Base
@@ -85,23 +87,20 @@ delete kq = do
return ()
modifyFd :: KQueue -> Fd -> E.Event -> E.Event -> IO Bool
-modifyFd kq fd oevt nevt
- | nevt == mempty = do
- let !ev = event fd (toFilter oevt) flagDelete noteEOF
- kqueueControl (kqueueFd kq) ev
- | otherwise = do
- let !ev = event fd (toFilter nevt) flagAdd noteEOF
- kqueueControl (kqueueFd kq) ev
-
-toFilter :: E.Event -> Filter
-toFilter evt
- | evt `E.eventIs` E.evtRead = filterRead
- | otherwise = filterWrite
+modifyFd kq fd oevt nevt = kqueueControl (kqueueFd kq) evs
+ where
+ evs
+ | nevt == mempty = toEvents fd (toFilter oevt) flagDelete noteEOF
+ | otherwise = toEvents fd (toFilter nevt) flagAdd noteEOF
+
+toFilter :: E.Event -> [Filter]
+toFilter e = catMaybes [ check E.evtRead filterRead, check E.evtWrite filterWrite ]
+ where
+ check e' f = if e `E.eventIs` e' then Just f else Nothing
modifyFdOnce :: KQueue -> Fd -> E.Event -> IO Bool
-modifyFdOnce kq fd evt = do
- let !ev = event fd (toFilter evt) (flagAdd .|. flagOneshot) noteEOF
- kqueueControl (kqueueFd kq) ev
+modifyFdOnce kq fd evt =
+ kqueueControl (kqueueFd kq) (toEvents fd (toFilter evt) (flagAdd .|. flagOneshot) noteEOF)
poll :: KQueue
-> Maybe Timeout
@@ -125,7 +124,9 @@ poll kq mtimeout f = do
newtype KQueueFd = KQueueFd {
fromKQueueFd :: CInt
- } deriving (Eq, Show)
+ } deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ )
data Event = KEvent {
ident :: {-# UNPACK #-} !CUIntPtr
@@ -138,10 +139,10 @@ data Event = KEvent {
, data_ :: {-# UNPACK #-} !CIntPtr
#endif
, udata :: {-# UNPACK #-} !(Ptr ())
- } deriving Show
+ } deriving Show -- ^ @since 4.4.0.0
-event :: Fd -> Filter -> Flag -> FFlag -> Event
-event fd filt flag fflag = KEvent (fromIntegral fd) filt flag fflag 0 nullPtr
+toEvents :: Fd -> [Filter] -> Flag -> FFlag -> [Event]
+toEvents fd flts flag fflag = map (\filt -> KEvent (fromIntegral fd) filt flag fflag 0 nullPtr) flts
-- | @since 4.3.1.0
instance Storable Event where
@@ -168,7 +169,10 @@ instance Storable Event where
#{poke struct kevent, udata} ptr (udata ev)
newtype FFlag = FFlag Word32
- deriving (Eq, Show, Storable)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ , Storable -- ^ @since 4.4.0.0
+ )
#{enum FFlag, FFlag
, noteEOF = NOTE_EOF
@@ -179,7 +183,13 @@ newtype Flag = Flag Word32
#else
newtype Flag = Flag Word16
#endif
- deriving (Bits, FiniteBits, Eq, Num, Show, Storable)
+ deriving ( Bits -- ^ @since 4.7.0.0
+ , FiniteBits -- ^ @since 4.7.0.0
+ , Eq -- ^ @since 4.4.0.0
+ , Num -- ^ @since 4.7.0.0
+ , Show -- ^ @since 4.4.0.0
+ , Storable -- ^ @since 4.4.0.0
+ )
#{enum Flag, Flag
, flagAdd = EV_ADD
@@ -192,7 +202,11 @@ newtype Filter = Filter Int32
#else
newtype Filter = Filter Int16
#endif
- deriving (Bits, FiniteBits, Eq, Num, Show, Storable)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Num -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ , Storable -- ^ @since 4.4.0.0
+ )
filterRead :: Filter
filterRead = Filter (#const EVFILT_READ)
@@ -222,11 +236,11 @@ instance Storable TimeSpec where
kqueue :: IO KQueueFd
kqueue = KQueueFd `fmap` throwErrnoIfMinus1 "kqueue" c_kqueue
-kqueueControl :: KQueueFd -> Event -> IO Bool
-kqueueControl kfd ev =
+kqueueControl :: KQueueFd -> [Event] -> IO Bool
+kqueueControl kfd evts =
withTimeSpec (TimeSpec 0 0) $ \tp ->
- withEvent ev $ \evp -> do
- res <- kevent False kfd evp 1 nullPtr 0 tp
+ withArrayLen evts $ \evlen evp -> do
+ res <- kevent False kfd evp evlen nullPtr 0 tp
if res == -1
then do
err <- getErrno
@@ -255,9 +269,6 @@ kevent safe k chs chlen evs evlen ts
| safe = c_kevent k chs (fromIntegral chlen) evs (fromIntegral evlen) ts
| otherwise = c_kevent_unsafe k chs (fromIntegral chlen) evs (fromIntegral evlen) ts
-withEvent :: Event -> (Ptr Event -> IO a) -> IO a
-withEvent ev f = alloca $ \ptr -> poke ptr ev >> f ptr
-
withTimeSpec :: TimeSpec -> (Ptr TimeSpec -> IO a) -> IO a
withTimeSpec ts f
| tv_sec ts < 0 = f nullPtr
diff --git a/libraries/base/GHC/Event/Manager.hs b/libraries/base/GHC/Event/Manager.hs
index 013850b5d2..3ee9116812 100644
--- a/libraries/base/GHC/Event/Manager.hs
+++ b/libraries/base/GHC/Event/Manager.hs
@@ -110,7 +110,9 @@ data FdData = FdData {
data FdKey = FdKey {
keyFd :: {-# UNPACK #-} !Fd
, keyUnique :: {-# UNPACK #-} !Unique
- } deriving (Eq, Show)
+ } deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ )
-- | Callback invoked on I/O events.
type IOCallback = FdKey -> Event -> IO ()
@@ -120,7 +122,9 @@ data State = Created
| Dying
| Releasing
| Finished
- deriving (Eq, Show)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ )
-- | The event manager state.
data EventManager = EventManager
diff --git a/libraries/base/GHC/Event/PSQ.hs b/libraries/base/GHC/Event/PSQ.hs
index 976ffe16b3..6e13839491 100644
--- a/libraries/base/GHC/Event/PSQ.hs
+++ b/libraries/base/GHC/Event/PSQ.hs
@@ -28,7 +28,7 @@ module GHC.Event.PSQ
, singleton
-- * Insertion
- , insert
+ , unsafeInsertNew
-- * Delete/Update
, delete
@@ -36,7 +36,6 @@ module GHC.Event.PSQ
-- * Conversion
, toList
- , fromList
-- * Min
, findMin
@@ -58,7 +57,7 @@ import GHC.Types (Int)
{-
-- Use macros to define strictness of functions.
--- STRICT_x_OF_y denotes an y-ary function strict in the x-th parameter.
+-- STRICT_x_OF_y denotes a y-ary function strict in the x-th parameter.
-- We do not use BangPatterns, because they are not in any standard and we
-- want the compilers to be compiled by as many compilers as possible.
#define STRICT_1_OF_2(fn) fn arg _ | arg `seq` False = undefined
@@ -213,14 +212,7 @@ singleton = Tip
-- Insertion
------------------------------------------------------------------------------
--- | /O(min(n,W))/ Insert a new key, priority and value into the queue. If the key
--- is already present in the queue, the associated priority and value are
--- replaced with the supplied priority and value.
-insert :: Key -> Prio -> v -> IntPSQ v -> IntPSQ v
-insert k p x t0 = unsafeInsertNew k p x (delete k t0)
-
--- | Internal function to insert a key that is *not* present in the priority
--- queue.
+-- | /O(min(n,W))/ Insert a new key that is *not* present in the priority queue.
{-# INLINABLE unsafeInsertNew #-}
unsafeInsertNew :: Key -> Prio -> v -> IntPSQ v -> IntPSQ v
unsafeInsertNew k p x = go
@@ -340,13 +332,6 @@ binShrinkR k p x m l r = Bin k p x m l r
-- Lists
------------------------------------------------------------------------------
--- | /O(n*min(n,W))/ Build a queue from a list of (key, priority, value) tuples.
--- If the list contains more than one priority and value for the same key, the
--- last priority and value for the key is retained.
-{-# INLINABLE fromList #-}
-fromList :: [Elem v] -> IntPSQ v
-fromList = foldr (\(E k p x) im -> insert k p x im) empty
-
-- | /O(n)/ Convert a queue to a list of (key, priority, value) tuples. The
-- order of the list is not specified.
toList :: IntPSQ v -> [Elem v]
diff --git a/libraries/base/GHC/Event/Poll.hsc b/libraries/base/GHC/Event/Poll.hsc
index 74525c6b40..1dafd601ec 100644
--- a/libraries/base/GHC/Event/Poll.hsc
+++ b/libraries/base/GHC/Event/Poll.hsc
@@ -151,10 +151,16 @@ data PollFd = PollFd {
pfdFd :: {-# UNPACK #-} !Fd
, pfdEvents :: {-# UNPACK #-} !Event
, pfdRevents :: {-# UNPACK #-} !Event
- } deriving (Show)
+ } deriving Show -- ^ @since 4.4.0.0
newtype Event = Event CShort
- deriving (Eq, Show, Num, Storable, Bits, FiniteBits)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Show -- ^ @since 4.4.0.0
+ , Num -- ^ @since 4.4.0.0
+ , Storable -- ^ @since 4.4.0.0
+ , Bits -- ^ @since 4.4.0.0
+ , FiniteBits -- ^ @since 4.7.0.0
+ )
-- We have to duplicate the whole enum like this in order for the
-- hsc2hs cross-compilation mode to work
diff --git a/libraries/base/GHC/Event/Thread.hs b/libraries/base/GHC/Event/Thread.hs
index d4b679206a..a9d5410d9c 100644
--- a/libraries/base/GHC/Event/Thread.hs
+++ b/libraries/base/GHC/Event/Thread.hs
@@ -72,7 +72,7 @@ registerDelay usecs = do
-- | Block the current thread until data is available to read from the
-- given file descriptor.
--
--- This will throw an 'IOError' if the file descriptor was closed
+-- This will throw an 'Prelude.IOError' if the file descriptor was closed
-- while this thread was blocked. To safely close a file descriptor
-- that has been used with 'threadWaitRead', use 'closeFdWith'.
threadWaitRead :: Fd -> IO ()
@@ -82,7 +82,7 @@ threadWaitRead = threadWait evtRead
-- | Block the current thread until the given file descriptor can
-- accept data to write.
--
--- This will throw an 'IOError' if the file descriptor was closed
+-- This will throw an 'Prelude.IOError' if the file descriptor was closed
-- while this thread was blocked. To safely close a file descriptor
-- that has been used with 'threadWaitWrite', use 'closeFdWith'.
threadWaitWrite :: Fd -> IO ()
@@ -145,7 +145,7 @@ threadWaitSTM evt fd = mask_ $ do
-- The second element of the return value pair is an IO action that can be used
-- to deregister interest in the file descriptor.
--
--- The STM action will throw an 'IOError' if the file descriptor was closed
+-- The STM action will throw an 'Prelude.IOError' if the file descriptor was closed
-- while the STM action is being executed. To safely close a file descriptor
-- that has been used with 'threadWaitReadSTM', use 'closeFdWith'.
threadWaitReadSTM :: Fd -> IO (STM (), IO ())
@@ -157,7 +157,7 @@ threadWaitReadSTM = threadWaitSTM evtRead
-- The second element of the return value pair is an IO action that can be used to deregister
-- interest in the file descriptor.
--
--- The STM action will throw an 'IOError' if the file descriptor was closed
+-- The STM action will throw an 'Prelude.IOError' if the file descriptor was closed
-- while the STM action is being executed. To safely close a file descriptor
-- that has been used with 'threadWaitWriteSTM', use 'closeFdWith'.
threadWaitWriteSTM :: Fd -> IO (STM (), IO ())
diff --git a/libraries/base/GHC/Event/TimerManager.hs b/libraries/base/GHC/Event/TimerManager.hs
index f3dbb21686..946f2333bf 100644
--- a/libraries/base/GHC/Event/TimerManager.hs
+++ b/libraries/base/GHC/Event/TimerManager.hs
@@ -43,11 +43,12 @@ import Data.Foldable (sequence_)
import Data.IORef (IORef, atomicModifyIORef', mkWeakIORef, newIORef, readIORef,
writeIORef)
import GHC.Base
+import GHC.Clock (getMonotonicTimeNSec)
import GHC.Conc.Signal (runHandlers)
+import GHC.Enum (maxBound)
import GHC.Num (Num(..))
-import GHC.Real (fromIntegral)
+import GHC.Real (quot, fromIntegral)
import GHC.Show (Show(..))
-import GHC.Event.Clock (getMonotonicTimeNSec)
import GHC.Event.Control
import GHC.Event.Internal (Backend, Event, evtRead, Timeout(..))
import GHC.Event.Unique (Unique, UniqueSource, newSource, newUnique)
@@ -67,7 +68,7 @@ import qualified GHC.Event.Poll as Poll
-- | A timeout registration cookie.
newtype TimeoutKey = TK Unique
- deriving (Eq)
+ deriving Eq -- ^ @since 4.7.0.0
-- | Callback invoked on timeout events.
type TimeoutCallback = IO ()
@@ -76,7 +77,9 @@ data State = Created
| Running
| Dying
| Finished
- deriving (Eq, Show)
+ deriving ( Eq -- ^ @since 4.7.0.0
+ , Show -- ^ @since 4.7.0.0
+ )
-- | A priority search queue, with timeouts as priorities.
type TimeoutQueue = Q.PSQ TimeoutCallback
@@ -206,6 +209,18 @@ wakeManager mgr = sendWakeup (emControl mgr)
------------------------------------------------------------------------
-- Registering interest in timeout events
+expirationTime :: Int -> IO Q.Prio
+expirationTime us = do
+ now <- getMonotonicTimeNSec
+ let 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.
+ | (maxBound - now) `quot` 1000 < fromIntegral us = maxBound
+ | otherwise = now + ns
+ where ns = 1000 * fromIntegral us
+ return 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
@@ -215,10 +230,11 @@ registerTimeout mgr us cb = do
!key <- newUnique (emUniqueSource mgr)
if us <= 0 then cb
else do
- now <- getMonotonicTimeNSec
- let expTime = fromIntegral us * 1000 + now
+ expTime <- expirationTime us
- editTimeouts mgr (Q.insert key expTime cb)
+ -- "unsafeInsertNew" is safe - the key must not exist in the PSQ. It
+ -- doesn't because we just generated it from a unique supply.
+ editTimeouts mgr (Q.unsafeInsertNew key expTime cb)
return $ TK key
-- | Unregister an active timeout.
@@ -230,9 +246,7 @@ unregisterTimeout mgr (TK key) = do
-- microseconds.
updateTimeout :: TimerManager -> TimeoutKey -> Int -> IO ()
updateTimeout mgr (TK key) us = do
- now <- getMonotonicTimeNSec
- let expTime = fromIntegral us * 1000 + now
-
+ expTime <- expirationTime us
editTimeouts mgr (Q.adjust (const expTime) key)
editTimeouts :: TimerManager -> TimeoutEdit -> IO ()
diff --git a/libraries/base/GHC/Event/Unique.hs b/libraries/base/GHC/Event/Unique.hs
index 0363af2068..1339bd97e7 100644
--- a/libraries/base/GHC/Event/Unique.hs
+++ b/libraries/base/GHC/Event/Unique.hs
@@ -19,7 +19,10 @@ import GHC.Show(Show(..))
data UniqueSource = US (MutableByteArray# RealWorld)
newtype Unique = Unique { asInt :: Int }
- deriving (Eq, Ord, Num)
+ deriving ( Eq -- ^ @since 4.4.0.0
+ , Ord -- ^ @since 4.4.0.0
+ , Num -- ^ @since 4.4.0.0
+ )
-- | @since 4.3.1.0
instance Show Unique where