[commit: base] : Allow backends to provide a command that register interest for an event source for exactly one event, and implement epoll implementation of this command. (11e074f)

Johan Tibell johan.tibell at gmail.com
Tue Feb 12 07:50:11 CET 2013


Repository : ssh://darcs.haskell.org//srv/darcs/packages/base

On branch  : 

http://hackage.haskell.org/trac/ghc/changeset/11e074fde8f30a6953fcf8c237fa4699fef3b1d2

>---------------------------------------------------------------

commit 11e074fde8f30a6953fcf8c237fa4699fef3b1d2
Author: Andreas Voellmy <andreas.voellmy at gmail.com>
Date:   Fri Dec 21 11:56:09 2012 -0500

    Allow backends to provide a command that register interest for an event source for exactly one event, and implement epoll implementation of this command.

>---------------------------------------------------------------

 GHC/Event/EPoll.hsc   |   28 +++++++++++++++++++++++-----
 GHC/Event/Internal.hs |   20 ++++++++++++++++----
 GHC/Event/KQueue.hsc  |    5 ++++-
 GHC/Event/Poll.hsc    |    5 ++++-
 4 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/GHC/Event/EPoll.hsc b/GHC/Event/EPoll.hsc
index 9a5084f..1f6e2e7 100644
--- a/GHC/Event/EPoll.hsc
+++ b/GHC/Event/EPoll.hsc
@@ -40,12 +40,13 @@ available = False
 
 #include <sys/epoll.h>
 
-import Control.Monad (when)
+import Control.Monad (unless, when)
 import Data.Bits (Bits, (.|.), (.&.))
 import Data.Maybe (Maybe(..))
 import Data.Monoid (Monoid(..))
 import Data.Word (Word32)
-import Foreign.C.Error (throwErrnoIfMinus1, throwErrnoIfMinus1_)
+import Foreign.C.Error (eNOENT, getErrno, throwErrno,
+                        throwErrnoIfMinus1, throwErrnoIfMinus1_)
 import Foreign.C.Types (CInt(..))
 import Foreign.Marshal.Utils (with)
 import Foreign.Ptr (Ptr)
@@ -76,7 +77,7 @@ new :: IO E.Backend
 new = do
   epfd <- epollCreate
   evts <- A.new 64
-  let !be = E.backend poll modifyFd delete (EPoll epfd evts)
+  let !be = E.backend poll modifyFd modifyFdOnce delete (EPoll epfd evts)
   return be
 
 delete :: EPoll -> IO ()
@@ -93,6 +94,18 @@ modifyFd ep fd oevt nevt = with (Event (fromEvent nevt) fd) $
            | nevt == mempty = controlOpDelete
            | otherwise      = controlOpModify
 
+modifyFdOnce :: EPoll -> Fd -> E.Event -> IO ()
+modifyFdOnce ep fd evt =
+  do let !ev = fromEvent evt .|. epollOneShot
+     res <- with (Event ev fd) $
+            epollControl_ (epollFd ep) controlOpModify fd
+     unless (res == 0) $ do
+         err <- getErrno
+         if err == eNOENT then
+             with (Event ev fd) $ epollControl (epollFd ep) controlOpAdd fd
+           else
+             throwErrno "modifyFdOnce"
+
 -- | Select a set of file descriptors which are ready for I/O
 -- operations and call @f@ for all ready file descriptors, passing the
 -- events that are ready.
@@ -155,6 +168,7 @@ newtype EventType = EventType {
  , epollOut = EPOLLOUT
  , epollErr = EPOLLERR
  , epollHup = EPOLLHUP
+ , epollOneShot = EPOLLONESHOT              
  }
 
 -- | Create a new epoll context, returning a file descriptor associated with the context.
@@ -174,8 +188,12 @@ epollCreate = do
   return epollFd'
 
 epollControl :: EPollFd -> ControlOp -> Fd -> Ptr Event -> IO ()
-epollControl (EPollFd epfd) (ControlOp op) (Fd fd) event =
-    throwErrnoIfMinus1_ "epollControl" $ c_epoll_ctl epfd op fd event
+epollControl epfd op fd event =
+    throwErrnoIfMinus1_ "epollControl" $ epollControl_ epfd op fd event
+
+epollControl_ :: EPollFd -> ControlOp -> Fd -> Ptr Event -> IO CInt
+epollControl_ (EPollFd epfd) (ControlOp op) (Fd fd) event =
+    c_epoll_ctl epfd op fd event
 
 epollWait :: EPollFd -> Ptr Event -> Int -> Int -> IO Int
 epollWait (EPollFd epfd) events numEvents timeout =
diff --git a/GHC/Event/Internal.hs b/GHC/Event/Internal.hs
index 9636941..7b25c86 100644
--- a/GHC/Event/Internal.hs
+++ b/GHC/Event/Internal.hs
@@ -9,6 +9,7 @@ module GHC.Event.Internal
     , delete
     , poll
     , modifyFd
+    , modifyFdOnce
     -- * Event type
     , Event
     , evtRead
@@ -103,27 +104,38 @@ data Backend = forall a. Backend {
                   -> Event    -- new events to watch for ('mempty' to delete)
                   -> IO ()
 
+    , _beModifyFdOnce :: a
+                         -> Fd    -- file descriptor
+                         -> Event -- new events to watch
+                         -> IO ()
+
     , _beDelete :: a -> IO ()
     }
 
 backend :: (a -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int)
         -> (a -> Fd -> Event -> Event -> IO ())
+        -> (a -> Fd -> Event -> IO ())
         -> (a -> IO ())
         -> a
         -> Backend
-backend bPoll bModifyFd bDelete state = Backend state bPoll bModifyFd bDelete
+backend bPoll bModifyFd bModifyFdOnce bDelete state =
+  Backend state bPoll bModifyFd bModifyFdOnce bDelete
 {-# INLINE backend #-}
 
 poll :: Backend -> Maybe Timeout -> (Fd -> Event -> IO ()) -> IO Int
-poll (Backend bState bPoll _ _) = bPoll bState
+poll (Backend bState bPoll _ _ _) = bPoll bState
 {-# INLINE poll #-}
 
 modifyFd :: Backend -> Fd -> Event -> Event -> IO ()
-modifyFd (Backend bState _ bModifyFd _) = bModifyFd bState
+modifyFd (Backend bState _ bModifyFd _ _) = bModifyFd bState
 {-# INLINE modifyFd #-}
 
+modifyFdOnce :: Backend -> Fd -> Event -> IO ()
+modifyFdOnce (Backend bState _ _ bModifyFdOnce _) = bModifyFdOnce bState
+{-# INLINE modifyFdOnce #-}
+
 delete :: Backend -> IO ()
-delete (Backend bState _ _ bDelete) = bDelete bState
+delete (Backend bState _ _ _ bDelete) = bDelete bState
 {-# INLINE delete #-}
 
 -- | Throw an 'IOError' corresponding to the current value of
diff --git a/GHC/Event/KQueue.hsc b/GHC/Event/KQueue.hsc
index 2db7b19..9aa47a3 100644
--- a/GHC/Event/KQueue.hsc
+++ b/GHC/Event/KQueue.hsc
@@ -86,7 +86,7 @@ new = do
   changesArr <- A.empty
   changes <- newMVar changesArr 
   events <- A.new 64
-  let !be = E.backend poll modifyFd delete (EventQueue qfd changes events)
+  let !be = E.backend poll modifyFd modifyFdOnce delete (EventQueue qfd changes events)
   return be
 
 delete :: EventQueue -> IO ()
@@ -102,6 +102,9 @@ modifyFd q fd oevt nevt = withMVar (eqChanges q) $ \ch -> do
   when (nevt `E.eventIs` E.evtRead)  $ addChange filterRead flagAdd
   when (nevt `E.eventIs` E.evtWrite) $ addChange filterWrite flagAdd
 
+modifyFdOnce :: EventQueue -> Fd -> E.Event -> IO ()
+modifyFdOnce = error "modifyFdOnce not supported in KQueue backend"
+
 poll :: EventQueue
      -> Maybe Timeout
      -> (Fd -> E.Event -> IO ())
diff --git a/GHC/Event/Poll.hsc b/GHC/Event/Poll.hsc
index a132bd4..d73d813 100644
--- a/GHC/Event/Poll.hsc
+++ b/GHC/Event/Poll.hsc
@@ -55,7 +55,7 @@ data Poll = Poll {
     }
 
 new :: IO E.Backend
-new = E.backend poll modifyFd (\_ -> return ()) `liftM`
+new = E.backend poll modifyFd modifyFdOnce (\_ -> return ()) `liftM`
       liftM2 Poll (newMVar =<< A.empty) A.empty
 
 modifyFd :: Poll -> Fd -> E.Event -> E.Event -> IO ()
@@ -63,6 +63,9 @@ modifyFd p fd oevt nevt =
   withMVar (pollChanges p) $ \ary ->
     A.snoc ary $ PollFd fd (fromEvent nevt) (fromEvent oevt)
 
+modifyFdOnce :: Poll -> Fd -> E.Event -> IO ()
+modifyFdOnce = error "modifyFdOnce not supported in Poll backend"
+
 reworkFd :: Poll -> PollFd -> IO ()
 reworkFd p (PollFd fd npevt opevt) = do
   let ary = pollFd p





More information about the ghc-commits mailing list