summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Event/Internal.hs
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2015-01-12 18:36:23 -0500
committerBen Gamari <bgamari.foss@gmail.com>2015-01-12 18:36:23 -0500
commit023439980f6ef6ec051f676279ed2be5f031efe6 (patch)
tree33c19b6f0654c8f2cb0a1ea9555ad6fb79dc94c0 /libraries/base/GHC/Event/Internal.hs
parent8464fa29e677e6845ca96d21474840803218f0b9 (diff)
downloadhaskell-023439980f6ef6ec051f676279ed2be5f031efe6.tar.gz
Event Manager: Make one-shot a per-registration property
Summary: Currently the event manager has a global flag for whether to create epoll-like notifications as one-shot (e.g. EPOLLONESHOT, where an fd will be deactivated after its first event) or standard multi-shot notifications. Unfortunately this means that the event manager may export either one-shot or multi-shot semantics to the user. Even worse, the user has no way of knowing which semantics are being delivered. This resulted in breakage in the usb[1] library which deadlocks after notifications on its fd are disabled after the first event is delivered. This patch reworks one-shot event support to allow the user to choose whether one-shot or multi-shot semantics are desired on a per-registration basis. The event manager can then decide whether to use a one-shot or multi-shot epoll. A registration is now defined by a set of Events (as before) as well as a Lifetime (either one-shot or multi-shot). We lend monoidal structure to Lifetime choosing OneShot as the identity. This allows us to combine Lifetime/Event pairs of an fd to give the longest desired lifetime of the registration and the full set of Events for which we want notification. [1] https://github.com/basvandijk/usb/issues/7 Test Plan: Add more test cases and validate Reviewers: tibbe, AndreasVoellmy, hvr, austin Reviewed By: austin Subscribers: thomie, carter, simonmar Differential Revision: https://phabricator.haskell.org/D347
Diffstat (limited to 'libraries/base/GHC/Event/Internal.hs')
-rw-r--r--libraries/base/GHC/Event/Internal.hs48
1 files changed, 48 insertions, 0 deletions
diff --git a/libraries/base/GHC/Event/Internal.hs b/libraries/base/GHC/Event/Internal.hs
index f1bd45ebc5..c18bd7f394 100644
--- a/libraries/base/GHC/Event/Internal.hs
+++ b/libraries/base/GHC/Event/Internal.hs
@@ -16,6 +16,12 @@ module GHC.Event.Internal
, evtWrite
, evtClose
, eventIs
+ -- * Lifetimes
+ , Lifetime(..)
+ , EventLifetime
+ , eventLifetime
+ , elLifetime
+ , elEvent
-- * Timeout type
, Timeout(..)
-- * Helpers
@@ -77,6 +83,46 @@ evtConcat :: [Event] -> Event
evtConcat = foldl' evtCombine evtNothing
{-# INLINE evtConcat #-}
+-- | The lifetime of a registration.
+data Lifetime = OneShot | MultiShot
+ deriving (Show, Eq)
+
+-- | The longer of two lifetimes.
+elSupremum :: Lifetime -> Lifetime -> Lifetime
+elSupremum OneShot OneShot = OneShot
+elSupremum _ _ = MultiShot
+{-# INLINE elSupremum #-}
+
+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)
+
+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)
+ where
+ lifetimeBit OneShot = 0
+ lifetimeBit MultiShot = 8
+{-# INLINE eventLifetime #-}
+
+elLifetime :: EventLifetime -> Lifetime
+elLifetime (EL x) = if x .&. 8 == 0 then OneShot else MultiShot
+{-# INLINE elLifetime #-}
+
+elEvent :: EventLifetime -> Event
+elEvent (EL x) = Event (x .&. 0x7)
+{-# INLINE elEvent #-}
+
-- | A type alias for timeouts, specified in seconds.
data Timeout = Timeout {-# UNPACK #-} !Double
| Forever
@@ -101,6 +147,8 @@ data Backend = forall a. Backend {
-> Event -- new events to watch for ('mempty' to delete)
-> IO Bool
+ -- | Register interest in new events on a given file descriptor, set
+ -- to be deactivated after the first event.
, _beModifyFdOnce :: a
-> Fd -- file descriptor
-> Event -- new events to watch