{-# LANGUAGE BangPatterns #-}{-# LANGUAGE CPP #-}{-# LANGUAGE ExistentialQuantification #-}{-# LANGUAGE FlexibleInstances #-}{-# LANGUAGE NoImplicitPrelude #-}{-# LANGUAGE RecordWildCards #-}{-# LANGUAGE Trustworthy #-}-- |-- The event manager supports event notification on fds. Each fd may-- have multiple callbacks registered, each listening for a different-- set of events. Registrations may be automatically deactivated after-- the occurrence of an event ("one-shot mode") or active until-- explicitly unregistered.---- If an fd has only one-shot registrations then we use one-shot-- polling if available. Otherwise we use multi-shot polling.moduleGHC.Event.Manager(-- * TypesEventManager -- * Creation,new ,newWith ,newDefaultBackend -- * Running,finished ,loop ,step ,shutdown ,release ,cleanup ,wakeManager -- * State,callbackTableVar ,emControl -- * Registering interest in I/O events,Lifetime (..),Event ,evtRead ,evtWrite ,IOCallback ,FdKey (keyFd ),FdData ,registerFd ,unregisterFd_ ,unregisterFd ,closeFd ,closeFd_ )where #include "EventConfig.h" -------------------------------------------------------------------------- ImportsimportControl.Concurrent.MVar (MVar ,newMVar ,putMVar ,tryPutMVar ,takeMVar ,withMVar )importControl.Exception (onException )importData.Bits ((.&.) )importData.Foldable (forM_ )importData.Functor (void )importData.IORef (IORef ,atomicModifyIORef' ,mkWeakIORef ,newIORef ,readIORef ,writeIORef )importData.Maybe (maybe )importData.OldList (partition )importGHC.Arr (Array ,(!) ,listArray )importGHC.Base importGHC.Conc.Sync (yield )importGHC.List (filter ,replicate )importGHC.Num (Num (..))importGHC.Real (fromIntegral )importGHC.Show (Show (..))importGHC.Event.Control importGHC.Event.IntTable (IntTable )importGHC.Event.Internal (Backend ,Event ,evtClose ,evtRead ,evtWrite ,Lifetime (..),EventLifetime ,Timeout (..))importGHC.Event.Unique (Unique ,UniqueSource ,newSource ,newUnique )importSystem.Posix.Types (Fd )importqualifiedGHC.Event.IntTable asITimportqualifiedGHC.Event.Internal asI #if defined(HAVE_KQUEUE) importqualifiedGHC.Event.KQueueasKQueue #elif defined(HAVE_EPOLL) importqualifiedGHC.Event.EPoll asEPoll #elif defined(HAVE_POLL) importqualifiedGHC.Event.PollasPoll #else # error not implemented for this operating system #endif -------------------------------------------------------------------------- TypesdataFdData =FdData {FdData -> FdKey fdKey ::{-# UNPACK#-}!FdKey ,FdData -> EventLifetime fdEvents ::{-# UNPACK#-}!EventLifetime ,FdData -> IOCallback _fdCallback ::!IOCallback }-- | A file descriptor registration cookie.dataFdKey =FdKey {FdKey -> Fd keyFd ::{-# UNPACK#-}!Fd ,FdKey -> Unique keyUnique ::{-# UNPACK#-}!Unique }deriving(FdKey -> FdKey -> Bool (FdKey -> FdKey -> Bool) -> (FdKey -> FdKey -> Bool) -> Eq FdKey forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: FdKey -> FdKey -> Bool == :: FdKey -> FdKey -> Bool $c/= :: FdKey -> FdKey -> Bool /= :: FdKey -> FdKey -> Bool Eq -- ^ @since 4.4.0.0,Int -> FdKey -> ShowS [FdKey] -> ShowS FdKey -> String (Int -> FdKey -> ShowS) -> (FdKey -> String) -> ([FdKey] -> ShowS) -> Show FdKey forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> FdKey -> ShowS showsPrec :: Int -> FdKey -> ShowS $cshow :: FdKey -> String show :: FdKey -> String $cshowList :: [FdKey] -> ShowS showList :: [FdKey] -> ShowS Show -- ^ @since 4.4.0.0)-- | Callback invoked on I/O events.typeIOCallback =FdKey ->Event ->IO ()dataState =Created |Running |Dying |Releasing |Finished deriving(State -> State -> Bool (State -> State -> Bool) -> (State -> State -> Bool) -> Eq State forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: State -> State -> Bool == :: State -> State -> Bool $c/= :: State -> State -> Bool /= :: State -> State -> Bool Eq -- ^ @since 4.4.0.0,Int -> State -> ShowS [State] -> ShowS State -> String (Int -> State -> ShowS) -> (State -> String) -> ([State] -> ShowS) -> Show State forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> State -> ShowS showsPrec :: Int -> State -> ShowS $cshow :: State -> String show :: State -> String $cshowList :: [State] -> ShowS showList :: [State] -> ShowS Show -- ^ @since 4.4.0.0)-- | The event manager state.dataEventManager =EventManager {EventManager -> Backend emBackend ::!Backend ,EventManager -> Array Int (MVar (IntTable [FdData])) emFds ::{-# UNPACK#-}!(Array Int (MVar (IntTable [FdData ]))),EventManager -> IORef State emState ::{-# UNPACK#-}!(IORef State ),EventManager -> UniqueSource emUniqueSource ::{-# UNPACK#-}!UniqueSource ,EventManager -> Control emControl ::{-# UNPACK#-}!Control ,EventManager -> MVar () emLock ::{-# UNPACK#-}!(MVar ())}-- must be power of 2callbackArraySize ::Int callbackArraySize :: Int callbackArraySize =Int 32hashFd ::Fd ->Int hashFd :: Fd -> Int hashFd Fd fd =Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd Int -> Int -> Int forall a. Bits a => a -> a -> a .&. (Int callbackArraySize Int -> Int -> Int forall a. Num a => a -> a -> a - Int 1){-# INLINEhashFd #-}callbackTableVar ::EventManager ->Fd ->MVar (IntTable [FdData ])callbackTableVar :: EventManager -> Fd -> MVar (IntTable [FdData]) callbackTableVar EventManager mgr Fd fd =EventManager -> Array Int (MVar (IntTable [FdData])) emFds EventManager mgr Array Int (MVar (IntTable [FdData])) -> Int -> MVar (IntTable [FdData]) forall i e. Ix i => Array i e -> i -> e ! Fd -> Int hashFd Fd fd {-# INLINEcallbackTableVar #-}haveOneShot ::Bool {-# INLINEhaveOneShot #-} #if defined(darwin_HOST_OS) || defined(ios_HOST_OS) haveOneShot=False #elif defined(HAVE_EPOLL) || defined(HAVE_KQUEUE) haveOneShot :: Bool haveOneShot =Bool True #else haveOneShot=False #endif -------------------------------------------------------------------------- CreationhandleControlEvent ::EventManager ->Fd ->Event ->IO ()handleControlEvent :: EventManager -> Fd -> Event -> IO () handleControlEvent EventManager mgr Fd fd Event _evt =doControlMessage msg <-Control -> Fd -> IO ControlMessage readControlMessage (EventManager -> Control emControl EventManager mgr )Fd fd caseControlMessage msg ofControlMessage CMsgWakeup ->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ()ControlMessage CMsgDie ->IORef State -> State -> IO () forall a. IORef a -> a -> IO () writeIORef (EventManager -> IORef State emState EventManager mgr )State Finished ControlMessage _->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ()newDefaultBackend ::IO Backend #if defined(HAVE_KQUEUE) newDefaultBackend=KQueue.new #elif defined(HAVE_EPOLL) newDefaultBackend :: IO Backend newDefaultBackend =IO Backend EPoll.new #elif defined(HAVE_POLL) newDefaultBackend=Poll.new #else newDefaultBackend=errorWithoutStackTrace"no back end for this platform" #endif -- | Create a new event manager.new ::IO EventManager new :: IO EventManager new =Backend -> IO EventManager newWith (Backend -> IO EventManager) -> IO Backend -> IO EventManager forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b =<< IO Backend newDefaultBackend -- | Create a new 'EventManager' with the given polling backend.newWith ::Backend ->IO EventManager newWith :: Backend -> IO EventManager newWith Backend be =doArray Int (MVar (IntTable [FdData])) iofds <-([MVar (IntTable [FdData])] -> Array Int (MVar (IntTable [FdData]))) -> IO [MVar (IntTable [FdData])] -> IO (Array Int (MVar (IntTable [FdData]))) forall a b. (a -> b) -> IO a -> IO b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap ((Int, Int) -> [MVar (IntTable [FdData])] -> Array Int (MVar (IntTable [FdData])) forall i e. Ix i => (i, i) -> [e] -> Array i e listArray (Int 0,Int callbackArraySize Int -> Int -> Int forall a. Num a => a -> a -> a - Int 1))(IO [MVar (IntTable [FdData])] -> IO (Array Int (MVar (IntTable [FdData])))) -> IO [MVar (IntTable [FdData])] -> IO (Array Int (MVar (IntTable [FdData]))) forall a b. (a -> b) -> a -> b $ Int -> IO (MVar (IntTable [FdData])) -> IO [MVar (IntTable [FdData])] forall {m :: * -> *} {a}. Monad m => Int -> m a -> m [a] replicateM Int callbackArraySize (IntTable [FdData] -> IO (MVar (IntTable [FdData])) forall a. a -> IO (MVar a) newMVar (IntTable [FdData] -> IO (MVar (IntTable [FdData]))) -> IO (IntTable [FdData]) -> IO (MVar (IntTable [FdData])) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b =<< Int -> IO (IntTable [FdData]) forall a. Int -> IO (IntTable a) IT.new Int 8)Control ctrl <-Bool -> IO Control newControl Bool False IORef 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 $ \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 MVar () lockVar <-() -> IO (MVar ()) forall a. a -> IO (MVar a) newMVar ()letmgr :: EventManager mgr =EventManager {emBackend :: Backend emBackend =Backend be ,emFds :: Array Int (MVar (IntTable [FdData])) emFds =Array Int (MVar (IntTable [FdData])) iofds ,emState :: IORef State emState =IORef State state ,emUniqueSource :: UniqueSource emUniqueSource =UniqueSource us ,emControl :: Control emControl =Control ctrl ,emLock :: MVar () emLock =MVar () lockVar }EventManager -> Fd -> Event -> IO () registerControlFd EventManager mgr (Control -> Fd controlReadFd Control ctrl )Event evtRead EventManager -> Fd -> Event -> IO () registerControlFd EventManager mgr (Control -> Fd wakeupReadFd Control ctrl )Event evtRead EventManager -> IO EventManager forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return EventManager mgr wherereplicateM :: Int -> m a -> m [a] replicateM Int n m a x =[m a] -> m [a] forall (m :: * -> *) a. Monad m => [m a] -> m [a] sequence (Int -> m a -> [m a] forall a. Int -> a -> [a] replicate Int n m a x )failOnInvalidFile ::String ->Fd ->IO Bool ->IO ()failOnInvalidFile :: String -> Fd -> IO Bool -> IO () failOnInvalidFile String loc Fd fd IO Bool m =doBool ok <-IO Bool m Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (Bool -> Bool not Bool ok )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ letmsg :: String msg =String "Failed while attempting to modify registration of file "String -> ShowS forall a. [a] -> [a] -> [a] ++ Fd -> String forall a. Show a => a -> String show Fd fd String -> ShowS forall a. [a] -> [a] -> [a] ++ String " at location "String -> ShowS forall a. [a] -> [a] -> [a] ++ String loc inString -> IO () forall a. String -> a errorWithoutStackTrace String msg registerControlFd ::EventManager ->Fd ->Event ->IO ()registerControlFd :: EventManager -> Fd -> Event -> IO () registerControlFd EventManager mgr Fd fd Event evs =String -> Fd -> IO Bool -> IO () failOnInvalidFile String "registerControlFd"Fd fd (IO Bool -> IO ()) -> IO Bool -> IO () forall a b. (a -> b) -> a -> b $ Backend -> Fd -> Event -> Event -> IO Bool I.modifyFd (EventManager -> Backend emBackend EventManager mgr )Fd fd Event forall a. Monoid a => a mempty Event evs -- | Asynchronously shuts down the event manager, if running.shutdown ::EventManager ->IO ()shutdown :: EventManager -> IO () shutdown EventManager mgr =doState state <-IORef State -> (State -> (State, State)) -> IO State forall a b. IORef a -> (a -> (a, b)) -> IO b atomicModifyIORef' (EventManager -> IORef State emState EventManager mgr )((State -> (State, State)) -> IO State) -> (State -> (State, State)) -> IO State forall a b. (a -> b) -> a -> b $ \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 (EventManager -> Control emControl EventManager mgr )-- | Asynchronously tell the thread executing the event-- manager loop to exit.release ::EventManager ->IO ()release :: EventManager -> IO () release EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. }=doState state <-IORef State -> (State -> (State, State)) -> IO State forall a b. IORef a -> (a -> (a, b)) -> IO b atomicModifyIORef' IORef State emState ((State -> (State, State)) -> IO State) -> (State -> (State, State)) -> IO State forall a b. (a -> b) -> a -> b $ \State s ->(State Releasing ,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 () sendWakeup Control emControl finished ::EventManager ->IO Bool finished :: EventManager -> IO Bool finished EventManager 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 (EventManager -> IORef State emState EventManager mgr )cleanup ::EventManager ->IO ()cleanup :: EventManager -> IO () cleanup EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. }=doIORef State -> State -> IO () forall a. IORef a -> a -> IO () writeIORef IORef State emState State Finished IO Bool -> IO () forall (f :: * -> *) a. Functor f => f a -> f () void (IO Bool -> IO ()) -> IO Bool -> IO () forall a b. (a -> b) -> a -> b $ MVar () -> () -> IO Bool forall a. MVar a -> a -> IO Bool tryPutMVar MVar () emLock ()Backend -> IO () I.delete Backend emBackend Control -> IO () closeControl Control emControl -------------------------------------------------------------------------- Event loop-- | Start handling events. This function loops until told to stop,-- using 'shutdown'.---- /Note/: This loop can only be run once per 'EventManager', as it-- closes all of its control resources when it finishes.loop ::EventManager ->IO ()loop :: EventManager -> IO () loop mgr :: EventManager mgr @EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. }=doIO () -> IO () forall (f :: * -> *) a. Functor f => f a -> f () void (IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ MVar () -> IO () forall a. MVar a -> IO a takeMVar MVar () emLock State state <-IORef State -> (State -> (State, State)) -> IO State forall a b. IORef a -> (a -> (a, b)) -> IO b atomicModifyIORef' IORef State emState ((State -> (State, State)) -> IO State) -> (State -> (State, State)) -> IO State forall a b. (a -> b) -> a -> b $ \State s ->caseState s ofState Created ->(State Running ,State s )State Releasing ->(State Running ,State s )State _->(State s ,State s )caseState state ofState Created ->IO () go IO () -> IO () -> IO () forall a b. IO a -> IO b -> IO a `onException` EventManager -> IO () cleanup EventManager mgr State Releasing ->IO () go IO () -> IO () -> IO () forall a b. IO a -> IO b -> IO a `onException` EventManager -> IO () cleanup EventManager mgr State Dying ->EventManager -> IO () cleanup EventManager mgr -- While a poll loop is never forked when the event manager is in the-- 'Finished' state, its state could read 'Finished' once the new thread-- actually runs. This is not an error, just an unfortunate race condition-- in Thread.restartPollLoop. See #8235State Finished ->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ()State _->doEventManager -> IO () cleanup EventManager mgr String -> IO () forall a. String -> a errorWithoutStackTrace (String -> IO ()) -> String -> IO () forall a b. (a -> b) -> a -> b $ String "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 =doState state <-EventManager -> IO State step EventManager mgr caseState state ofState Running ->IO () yield IO () -> IO () -> IO () forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> IO () go State Releasing ->MVar () -> () -> IO () forall a. MVar a -> a -> IO () putMVar MVar () emLock ()State _->EventManager -> IO () cleanup EventManager mgr -- | To make a step, we first do a non-blocking poll, in case-- there are already events ready to handle. This improves performance-- because we can make an unsafe foreign C call, thereby avoiding-- forcing the current Task to release the Capability and forcing a context switch.-- If the poll fails to find events, we yield, putting the poll loop thread at-- end of the Haskell run queue. When it comes back around, we do one more-- non-blocking poll, in case we get lucky and have ready events.-- If that also returns no events, then we do a blocking poll.step ::EventManager ->IO State step :: EventManager -> IO State step mgr :: EventManager mgr @EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. }=doIO () waitForIO State state <-IORef State -> IO State forall a. IORef a -> IO a readIORef IORef State emState State state State -> IO State -> IO State forall a b. a -> b -> b `seq` State -> IO State forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return State state wherewaitForIO :: IO () waitForIO =doInt n1 <-Backend -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int I.poll Backend emBackend Maybe Timeout forall a. Maybe a Nothing (EventManager -> Fd -> Event -> IO () onFdEvent EventManager mgr )Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (Int n1 Int -> Int -> Bool forall a. Ord a => a -> a -> Bool <= Int 0)(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ doIO () yield Int n2 <-Backend -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int I.poll Backend emBackend Maybe Timeout forall a. Maybe a Nothing (EventManager -> Fd -> Event -> IO () onFdEvent EventManager mgr )Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (Int n2 Int -> Int -> Bool forall a. Ord a => a -> a -> Bool <= Int 0)(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ doInt _<-Backend -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int I.poll Backend emBackend (Timeout -> Maybe Timeout forall a. a -> Maybe a Just Timeout Forever )(EventManager -> Fd -> Event -> IO () onFdEvent EventManager mgr )() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ()-------------------------------------------------------------------------- Registering interest in I/O events-- | Register interest in the given events, without waking the event-- manager thread. The 'Bool' return value indicates whether the-- event manager ought to be woken.---- Note that the event manager is generally implemented in terms of the-- platform's @select@ or @epoll@ system call, which tend to vary in-- what sort of fds are permitted. For instance, waiting on regular files-- is not allowed on many platforms.registerFd_ ::EventManager ->IOCallback ->Fd ->Event ->Lifetime ->IO (FdKey ,Bool )registerFd_ :: EventManager -> IOCallback -> Fd -> Event -> Lifetime -> IO (FdKey, Bool) registerFd_ mgr :: EventManager mgr @(EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. })IOCallback cb Fd fd Event evs Lifetime lt =doUnique u <-UniqueSource -> IO Unique newUnique UniqueSource emUniqueSource letfd' :: Int fd' =Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd reg :: FdKey reg =Fd -> Unique -> FdKey FdKey Fd fd Unique u el :: EventLifetime el =Event -> Lifetime -> EventLifetime I.eventLifetime Event evs Lifetime lt !fdd :: FdData fdd =FdKey -> EventLifetime -> IOCallback -> FdData FdData FdKey reg EventLifetime el IOCallback cb (Bool modify ,Bool ok )<-MVar (IntTable [FdData]) -> (IntTable [FdData] -> IO (Bool, Bool)) -> IO (Bool, Bool) forall a b. MVar a -> (a -> IO b) -> IO b withMVar (EventManager -> Fd -> MVar (IntTable [FdData]) callbackTableVar EventManager mgr Fd fd )((IntTable [FdData] -> IO (Bool, Bool)) -> IO (Bool, Bool)) -> (IntTable [FdData] -> IO (Bool, Bool)) -> IO (Bool, Bool) forall a b. (a -> b) -> a -> b $ \IntTable [FdData] tbl ->doMaybe [FdData] oldFdd <-([FdData] -> [FdData] -> [FdData]) -> Int -> [FdData] -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. (a -> a -> a) -> Int -> a -> IntTable a -> IO (Maybe a) IT.insertWith [FdData] -> [FdData] -> [FdData] forall a. [a] -> [a] -> [a] (++) Int fd' [FdData fdd ]IntTable [FdData] tbl letprevEvs ::EventLifetime prevEvs :: EventLifetime prevEvs =EventLifetime -> ([FdData] -> EventLifetime) -> Maybe [FdData] -> EventLifetime forall b a. b -> (a -> b) -> Maybe a -> b maybe EventLifetime forall a. Monoid a => a mempty [FdData] -> EventLifetime eventsOf Maybe [FdData] oldFdd el' ::EventLifetime el' :: EventLifetime el' =EventLifetime prevEvs EventLifetime -> EventLifetime -> EventLifetime forall a. Monoid a => a -> a -> a `mappend` EventLifetime el caseEventLifetime -> Lifetime I.elLifetime EventLifetime el' of-- All registrations want one-shot semantics and this is supportedLifetime OneShot |Bool haveOneShot ->doBool ok <-Backend -> Fd -> Event -> IO Bool I.modifyFdOnce Backend emBackend Fd fd (EventLifetime -> Event I.elEvent EventLifetime el' )ifBool ok then(Bool, Bool) -> IO (Bool, Bool) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (Bool False ,Bool True )elseInt -> Maybe [FdData] -> IntTable [FdData] -> IO () forall a. Int -> Maybe a -> IntTable a -> IO () IT.reset Int fd' Maybe [FdData] oldFdd IntTable [FdData] tbl IO () -> IO (Bool, Bool) -> IO (Bool, Bool) forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> (Bool, Bool) -> IO (Bool, Bool) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (Bool False ,Bool False )-- We don't want or don't support one-shot semanticsLifetime _->doletmodify :: Bool modify =EventLifetime prevEvs EventLifetime -> EventLifetime -> Bool forall a. Eq a => a -> a -> Bool /= EventLifetime el' Bool ok <-ifBool modify thenletnewEvs :: Event newEvs =EventLifetime -> Event I.elEvent EventLifetime el' oldEvs :: Event oldEvs =EventLifetime -> Event I.elEvent EventLifetime prevEvs inBackend -> Fd -> Event -> Event -> IO Bool I.modifyFd Backend emBackend Fd fd Event oldEvs Event newEvs elseBool -> IO Bool forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return Bool True ifBool ok then(Bool, Bool) -> IO (Bool, Bool) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (Bool modify ,Bool True )elseInt -> Maybe [FdData] -> IntTable [FdData] -> IO () forall a. Int -> Maybe a -> IntTable a -> IO () IT.reset Int fd' Maybe [FdData] oldFdd IntTable [FdData] tbl IO () -> IO (Bool, Bool) -> IO (Bool, Bool) forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> (Bool, Bool) -> IO (Bool, Bool) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (Bool False ,Bool False )-- this simulates behavior of old IO manager:-- i.e. just call the callback if the registration fails.Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (Bool -> Bool not Bool ok )(IOCallback cb FdKey reg Event evs )(FdKey, Bool) -> IO (FdKey, Bool) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (FdKey reg ,Bool modify ){-# INLINEregisterFd_ #-}-- | @registerFd mgr cb fd evs lt@ registers interest in the events @evs@-- on the file descriptor @fd@ for lifetime @lt@. @cb@ is called for-- each event that occurs. Returns a cookie that can be handed to-- 'unregisterFd'.registerFd ::EventManager ->IOCallback ->Fd ->Event ->Lifetime ->IO FdKey registerFd :: EventManager -> IOCallback -> Fd -> Event -> Lifetime -> IO FdKey registerFd EventManager mgr IOCallback cb Fd fd Event evs Lifetime lt =do(FdKey r ,Bool wake )<-EventManager -> IOCallback -> Fd -> Event -> Lifetime -> IO (FdKey, Bool) registerFd_ EventManager mgr IOCallback cb Fd fd Event evs Lifetime lt Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when Bool wake (IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ EventManager -> IO () wakeManager EventManager mgr FdKey -> IO FdKey forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return FdKey r {-# INLINEregisterFd #-}{- Building GHC with parallel IO manager on Mac freezes when compiling the dph libraries in the phase 2. As workaround, we don't use oneshot and we wake up an IO manager on Mac every time when we register an event. For more information, please read: https://gitlab.haskell.org/ghc/ghc/issues/7651 -}-- | Wake up the event manager.wakeManager ::EventManager ->IO () #if defined(darwin_HOST_OS) || defined(ios_HOST_OS) wakeManagermgr=sendWakeup(emControlmgr) #elif defined(HAVE_EPOLL) || defined(HAVE_KQUEUE) wakeManager :: EventManager -> IO () wakeManager EventManager _=() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return () #else wakeManagermgr=sendWakeup(emControlmgr) #endif eventsOf ::[FdData ]->EventLifetime eventsOf :: [FdData] -> EventLifetime eventsOf [FdData fdd ]=FdData -> EventLifetime fdEvents FdData fdd eventsOf [FdData] fdds =[EventLifetime] -> EventLifetime forall a. Monoid a => [a] -> a mconcat ([EventLifetime] -> EventLifetime) -> [EventLifetime] -> EventLifetime forall a b. (a -> b) -> a -> b $ (FdData -> EventLifetime) -> [FdData] -> [EventLifetime] forall a b. (a -> b) -> [a] -> [b] map FdData -> EventLifetime fdEvents [FdData] fdds -- | Drop a previous file descriptor registration, without waking the-- event manager thread. The return value indicates whether the event-- manager ought to be woken.unregisterFd_ ::EventManager ->FdKey ->IO Bool unregisterFd_ :: EventManager -> FdKey -> IO Bool unregisterFd_ mgr :: EventManager mgr @(EventManager {Array Int (MVar (IntTable [FdData])) MVar () UniqueSource IORef State Backend Control emControl :: EventManager -> Control emBackend :: EventManager -> Backend emFds :: EventManager -> Array Int (MVar (IntTable [FdData])) emState :: EventManager -> IORef State emUniqueSource :: EventManager -> UniqueSource emLock :: EventManager -> MVar () emBackend :: Backend emFds :: Array Int (MVar (IntTable [FdData])) emState :: IORef State emUniqueSource :: UniqueSource emControl :: Control emLock :: MVar () .. })(FdKey Fd fd Unique u )=MVar (IntTable [FdData]) -> (IntTable [FdData] -> IO Bool) -> IO Bool forall a b. MVar a -> (a -> IO b) -> IO b withMVar (EventManager -> Fd -> MVar (IntTable [FdData]) callbackTableVar EventManager mgr Fd fd )((IntTable [FdData] -> IO Bool) -> IO Bool) -> (IntTable [FdData] -> IO Bool) -> IO Bool forall a b. (a -> b) -> a -> b $ \IntTable [FdData] tbl ->doletdropReg :: [FdData] -> Maybe [FdData] dropReg =[FdData] -> Maybe [FdData] forall a. [a] -> Maybe [a] nullToNothing ([FdData] -> Maybe [FdData]) -> ([FdData] -> [FdData]) -> [FdData] -> Maybe [FdData] forall b c a. (b -> c) -> (a -> b) -> a -> c . (FdData -> Bool) -> [FdData] -> [FdData] forall a. (a -> Bool) -> [a] -> [a] filter ((Unique -> Unique -> Bool forall a. Eq a => a -> a -> Bool /= Unique u )(Unique -> Bool) -> (FdData -> Unique) -> FdData -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . FdKey -> Unique keyUnique (FdKey -> Unique) -> (FdData -> FdKey) -> FdData -> Unique forall b c a. (b -> c) -> (a -> b) -> a -> c . FdData -> FdKey fdKey )fd' :: Int fd' =Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd pairEvents ::[FdData ]->IO (EventLifetime ,EventLifetime )pairEvents :: [FdData] -> IO (EventLifetime, EventLifetime) pairEvents [FdData] prev =doEventLifetime r <-EventLifetime -> ([FdData] -> EventLifetime) -> Maybe [FdData] -> EventLifetime forall b a. b -> (a -> b) -> Maybe a -> b maybe EventLifetime forall a. Monoid a => a mempty [FdData] -> EventLifetime eventsOf (Maybe [FdData] -> EventLifetime) -> IO (Maybe [FdData]) -> IO EventLifetime forall a b. (a -> b) -> IO a -> IO b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b `fmap` Int -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. Int -> IntTable a -> IO (Maybe a) IT.lookup Int fd' IntTable [FdData] tbl (EventLifetime, EventLifetime) -> IO (EventLifetime, EventLifetime) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ([FdData] -> EventLifetime eventsOf [FdData] prev ,EventLifetime r )(EventLifetime oldEls ,EventLifetime newEls )<-([FdData] -> Maybe [FdData]) -> Int -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. (a -> Maybe a) -> Int -> IntTable a -> IO (Maybe a) IT.updateWith [FdData] -> Maybe [FdData] dropReg Int fd' IntTable [FdData] tbl IO (Maybe [FdData]) -> (Maybe [FdData] -> IO (EventLifetime, EventLifetime)) -> IO (EventLifetime, EventLifetime) forall a b. IO a -> (a -> IO b) -> IO b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= IO (EventLifetime, EventLifetime) -> ([FdData] -> IO (EventLifetime, EventLifetime)) -> Maybe [FdData] -> IO (EventLifetime, EventLifetime) forall b a. b -> (a -> b) -> Maybe a -> b maybe ((EventLifetime, EventLifetime) -> IO (EventLifetime, EventLifetime) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (EventLifetime forall a. Monoid a => a mempty ,EventLifetime forall a. Monoid a => a mempty ))[FdData] -> IO (EventLifetime, EventLifetime) pairEvents letmodify :: Bool modify =EventLifetime oldEls EventLifetime -> EventLifetime -> Bool forall a. Eq a => a -> a -> Bool /= EventLifetime newEls Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when Bool modify (IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ String -> Fd -> IO Bool -> IO () failOnInvalidFile String "unregisterFd_"Fd fd (IO Bool -> IO ()) -> IO Bool -> IO () forall a b. (a -> b) -> a -> b $ caseEventLifetime -> Lifetime I.elLifetime EventLifetime newEls ofLifetime OneShot |EventLifetime -> Event I.elEvent EventLifetime newEls Event -> Event -> Bool forall a. Eq a => a -> a -> Bool /= Event forall a. Monoid a => a mempty ,Bool haveOneShot ->Backend -> Fd -> Event -> IO Bool I.modifyFdOnce Backend emBackend Fd fd (EventLifetime -> Event I.elEvent EventLifetime newEls )Lifetime _->Backend -> Fd -> Event -> Event -> IO Bool I.modifyFd Backend emBackend Fd fd (EventLifetime -> Event I.elEvent EventLifetime oldEls )(EventLifetime -> Event I.elEvent EventLifetime newEls )Bool -> IO Bool forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return Bool modify -- | Drop a previous file descriptor registration.unregisterFd ::EventManager ->FdKey ->IO ()unregisterFd :: EventManager -> FdKey -> IO () unregisterFd EventManager mgr FdKey reg =doBool wake <-EventManager -> FdKey -> IO Bool unregisterFd_ EventManager mgr FdKey reg Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when Bool wake (IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ EventManager -> IO () wakeManager EventManager mgr -- | Close a file descriptor in a race-safe way. It might block, although for-- a very short time; and thus it is interruptible by asynchronous exceptions.closeFd ::EventManager ->(Fd ->IO ())->Fd ->IO ()closeFd :: EventManager -> (Fd -> IO ()) -> Fd -> IO () closeFd EventManager mgr Fd -> IO () close Fd fd =do[FdData] fds <-MVar (IntTable [FdData]) -> (IntTable [FdData] -> IO [FdData]) -> IO [FdData] forall a b. MVar a -> (a -> IO b) -> IO b withMVar (EventManager -> Fd -> MVar (IntTable [FdData]) callbackTableVar EventManager mgr Fd fd )((IntTable [FdData] -> IO [FdData]) -> IO [FdData]) -> (IntTable [FdData] -> IO [FdData]) -> IO [FdData] forall a b. (a -> b) -> a -> b $ \IntTable [FdData] tbl ->doMaybe [FdData] prev <-Int -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. Int -> IntTable a -> IO (Maybe a) IT.delete (Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd )IntTable [FdData] tbl caseMaybe [FdData] prev ofMaybe [FdData] Nothing ->Fd -> IO () close Fd fd IO () -> IO [FdData] -> IO [FdData] forall a b. IO a -> IO b -> IO b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> [FdData] -> IO [FdData] forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return []Just [FdData] fds ->doletoldEls :: EventLifetime oldEls =[FdData] -> EventLifetime eventsOf [FdData] fds Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (EventLifetime -> Event I.elEvent EventLifetime oldEls Event -> Event -> Bool forall a. Eq a => a -> a -> Bool /= Event forall a. Monoid a => a mempty )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ doBool _<-Backend -> Fd -> Event -> Event -> IO Bool I.modifyFd (EventManager -> Backend emBackend EventManager mgr )Fd fd (EventLifetime -> Event I.elEvent EventLifetime oldEls )Event forall a. Monoid a => a mempty EventManager -> IO () wakeManager EventManager mgr Fd -> IO () close Fd fd [FdData] -> IO [FdData] forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return [FdData] fds [FdData] -> (FdData -> IO ()) -> IO () forall (t :: * -> *) (m :: * -> *) a b. (Foldable t, Monad m) => t a -> (a -> m b) -> m () forM_ [FdData] fds ((FdData -> IO ()) -> IO ()) -> (FdData -> IO ()) -> IO () forall a b. (a -> b) -> a -> b $ \(FdData FdKey reg EventLifetime el IOCallback cb )->IOCallback cb FdKey reg (EventLifetime -> Event I.elEvent EventLifetime el Event -> Event -> Event forall a. Monoid a => a -> a -> a `mappend` Event evtClose )-- | Close a file descriptor in a race-safe way.-- It assumes the caller will update the callback tables and that the caller-- holds the callback table lock for the fd. It must hold this lock because-- this command executes a backend command on the fd.closeFd_ ::EventManager ->IntTable [FdData ]->Fd ->IO (IO ())closeFd_ :: EventManager -> IntTable [FdData] -> Fd -> IO (IO ()) closeFd_ EventManager mgr IntTable [FdData] tbl Fd fd =doMaybe [FdData] prev <-Int -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. Int -> IntTable a -> IO (Maybe a) IT.delete (Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd )IntTable [FdData] tbl caseMaybe [FdData] prev ofMaybe [FdData] Nothing ->IO () -> IO (IO ()) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ())Just [FdData] fds ->doletoldEls :: EventLifetime oldEls =[FdData] -> EventLifetime eventsOf [FdData] fds Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (EventLifetime oldEls EventLifetime -> EventLifetime -> Bool forall a. Eq a => a -> a -> Bool /= EventLifetime forall a. Monoid a => a mempty )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ doBool _<-Backend -> Fd -> Event -> Event -> IO Bool I.modifyFd (EventManager -> Backend emBackend EventManager mgr )Fd fd (EventLifetime -> Event I.elEvent EventLifetime oldEls )Event forall a. Monoid a => a mempty EventManager -> IO () wakeManager EventManager mgr IO () -> IO (IO ()) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return (IO () -> IO (IO ())) -> IO () -> IO (IO ()) forall a b. (a -> b) -> a -> b $ [FdData] -> (FdData -> IO ()) -> IO () forall (t :: * -> *) (m :: * -> *) a b. (Foldable t, Monad m) => t a -> (a -> m b) -> m () forM_ [FdData] fds ((FdData -> IO ()) -> IO ()) -> (FdData -> IO ()) -> IO () forall a b. (a -> b) -> a -> b $ \(FdData FdKey reg EventLifetime el IOCallback cb )->IOCallback cb FdKey reg (EventLifetime -> Event I.elEvent EventLifetime el Event -> Event -> Event forall a. Monoid a => a -> a -> a `mappend` Event evtClose )-------------------------------------------------------------------------- Utilities-- | Call the callbacks corresponding to the given file descriptor.onFdEvent ::EventManager ->Fd ->Event ->IO ()onFdEvent :: EventManager -> Fd -> Event -> IO () onFdEvent EventManager mgr Fd fd Event evs |Fd fd Fd -> Fd -> Bool forall a. Eq a => a -> a -> Bool == Control -> Fd controlReadFd (EventManager -> Control emControl EventManager mgr )Bool -> Bool -> Bool || Fd fd Fd -> Fd -> Bool forall a. Eq a => a -> a -> Bool == Control -> Fd wakeupReadFd (EventManager -> Control emControl EventManager mgr )=EventManager -> Fd -> Event -> IO () handleControlEvent EventManager mgr Fd fd Event evs |Bool otherwise =do[FdData] fdds <-MVar (IntTable [FdData]) -> (IntTable [FdData] -> IO [FdData]) -> IO [FdData] forall a b. MVar a -> (a -> IO b) -> IO b withMVar (EventManager -> Fd -> MVar (IntTable [FdData]) callbackTableVar EventManager mgr Fd fd )((IntTable [FdData] -> IO [FdData]) -> IO [FdData]) -> (IntTable [FdData] -> IO [FdData]) -> IO [FdData] forall a b. (a -> b) -> a -> b $ \IntTable [FdData] tbl ->Int -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. Int -> IntTable a -> IO (Maybe a) IT.delete (Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd )IntTable [FdData] tbl IO (Maybe [FdData]) -> (Maybe [FdData] -> IO [FdData]) -> IO [FdData] forall a b. IO a -> (a -> IO b) -> IO b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= IO [FdData] -> ([FdData] -> IO [FdData]) -> Maybe [FdData] -> IO [FdData] forall b a. b -> (a -> b) -> Maybe a -> b maybe ([FdData] -> IO [FdData] forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return [])(IntTable [FdData] -> [FdData] -> IO [FdData] selectCallbacks IntTable [FdData] tbl )[FdData] -> (FdData -> IO ()) -> IO () forall (t :: * -> *) (m :: * -> *) a b. (Foldable t, Monad m) => t a -> (a -> m b) -> m () forM_ [FdData] fdds ((FdData -> IO ()) -> IO ()) -> (FdData -> IO ()) -> IO () forall a b. (a -> b) -> a -> b $ \(FdData FdKey reg EventLifetime _IOCallback cb )->IOCallback cb FdKey reg Event evs where-- Here we look through the list of registrations for the fd of interest-- and sort out which match the events that were triggered. We,---- 1. re-arm the fd as appropriate-- 2. reinsert registrations that weren't triggered and multishot-- registrations-- 3. return a list containing the callbacks that should be invoked.selectCallbacks ::IntTable [FdData ]->[FdData ]->IO [FdData ]selectCallbacks :: IntTable [FdData] -> [FdData] -> IO [FdData] selectCallbacks IntTable [FdData] tbl [FdData] fdds =dolet-- figure out which registrations have been triggeredmatches ::FdData ->Bool matches :: FdData -> Bool matches FdData fd' =Event evs Event -> Event -> Bool `I.eventIs` EventLifetime -> Event I.elEvent (FdData -> EventLifetime fdEvents FdData fd' )([FdData] triggered ,[FdData] notTriggered )=(FdData -> Bool) -> [FdData] -> ([FdData], [FdData]) forall a. (a -> Bool) -> [a] -> ([a], [a]) partition FdData -> Bool matches [FdData] fdds -- sort out which registrations we need to retainisMultishot ::FdData ->Bool isMultishot :: FdData -> Bool isMultishot FdData fd' =EventLifetime -> Lifetime I.elLifetime (FdData -> EventLifetime fdEvents FdData fd' )Lifetime -> Lifetime -> Bool forall a. Eq a => a -> a -> Bool == Lifetime MultiShot saved :: [FdData] saved =[FdData] notTriggered [FdData] -> [FdData] -> [FdData] forall a. [a] -> [a] -> [a] ++ (FdData -> Bool) -> [FdData] -> [FdData] forall a. (a -> Bool) -> [a] -> [a] filter FdData -> Bool isMultishot [FdData] triggered savedEls :: EventLifetime savedEls =[FdData] -> EventLifetime eventsOf [FdData] saved allEls :: EventLifetime allEls =[FdData] -> EventLifetime eventsOf [FdData] fdds -- Reinsert multishot registrations.-- We deleted the table entry for this fd above so we there isn't a preexisting entryMaybe [FdData] _<-([FdData] -> [FdData] -> [FdData]) -> Int -> [FdData] -> IntTable [FdData] -> IO (Maybe [FdData]) forall a. (a -> a -> a) -> Int -> a -> IntTable a -> IO (Maybe a) IT.insertWith (\[FdData] _[FdData] _->[FdData] saved )(Fd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd )[FdData] saved IntTable [FdData] tbl caseEventLifetime -> Lifetime I.elLifetime EventLifetime allEls of-- we previously armed the fd for multiple shots, no need to rearmLifetime MultiShot |EventLifetime allEls EventLifetime -> EventLifetime -> Bool forall a. Eq a => a -> a -> Bool == EventLifetime savedEls ->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return ()-- either we previously registered for one shot or the-- events of interest have changed, we must re-armLifetime _->caseEventLifetime -> Lifetime I.elLifetime EventLifetime savedEls ofLifetime OneShot |Bool haveOneShot ->-- if there are no saved events and we registered with one-shot-- semantics then there is no need to re-armBool -> IO () -> IO () forall (m :: * -> *). Monad m => Bool -> m () -> m () unless (Lifetime OneShot Lifetime -> Lifetime -> Bool forall a. Eq a => a -> a -> Bool == EventLifetime -> Lifetime I.elLifetime EventLifetime allEls Bool -> Bool -> Bool && Event forall a. Monoid a => a mempty Event -> Event -> Bool forall a. Eq a => a -> a -> Bool == EventLifetime -> Event I.elEvent EventLifetime savedEls )(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $ IO Bool -> IO () forall (f :: * -> *) a. Functor f => f a -> f () void (IO Bool -> IO ()) -> IO Bool -> IO () forall a b. (a -> b) -> a -> b $ Backend -> Fd -> Event -> IO Bool I.modifyFdOnce (EventManager -> Backend emBackend EventManager mgr )Fd fd (EventLifetime -> Event I.elEvent EventLifetime savedEls )Lifetime _->-- we need to re-arm with multi-shot semanticsIO Bool -> IO () forall (f :: * -> *) a. Functor f => f a -> f () void (IO Bool -> IO ()) -> IO Bool -> IO () forall a b. (a -> b) -> a -> b $ Backend -> Fd -> Event -> Event -> IO Bool I.modifyFd (EventManager -> Backend emBackend EventManager mgr )Fd fd (EventLifetime -> Event I.elEvent EventLifetime allEls )(EventLifetime -> Event I.elEvent EventLifetime savedEls )[FdData] -> IO [FdData] forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return [FdData] triggered nullToNothing ::[a ]->Maybe [a ]nullToNothing :: forall a. [a] -> Maybe [a] nullToNothing []=Maybe [a] forall a. Maybe a Nothing nullToNothing xs :: [a] xs @(a _: [a] _)=[a] -> Maybe [a] forall a. a -> Maybe a Just [a] xs unless ::Monad m =>Bool ->m ()->m ()unless :: forall (m :: * -> *). Monad m => Bool -> m () -> m () unless Bool p =Bool -> m () -> m () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when (Bool -> Bool not Bool p )