[commit: base] : Apply the epoll backend design (separate polling from registration) for the KQueue backend. (e5f5cfc)
Johan Tibell
johan.tibell at gmail.com
Tue Feb 12 07:50:33 CET 2013
Repository : ssh://darcs.haskell.org//srv/darcs/packages/base
On branch :
http://hackage.haskell.org/trac/ghc/changeset/e5f5cfcd62a589b0784528d3b1f415a0a8fd2f07
>---------------------------------------------------------------
commit e5f5cfcd62a589b0784528d3b1f415a0a8fd2f07
Author: Andreas Voellmy <andreas.voellmy at gmail.com>
Date: Fri Dec 21 12:33:06 2012 -0500
Apply the epoll backend design (separate polling from registration) for the KQueue backend.
This design follows Kazu Yamamoto's implementation for KQueue.
>---------------------------------------------------------------
GHC/Event/KQueue.hsc | 53 +++++++++++++++++++++++++------------------------
1 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/GHC/Event/KQueue.hsc b/GHC/Event/KQueue.hsc
index 9aa47a3..7e467e9 100644
--- a/GHC/Event/KQueue.hsc
+++ b/GHC/Event/KQueue.hsc
@@ -28,10 +28,10 @@ available = False
{-# INLINE available #-}
#else
-import Control.Concurrent.MVar (MVar, newMVar, swapMVar, withMVar)
-import Control.Monad (when, unless)
+import Control.Monad (when, void)
import Data.Bits (Bits(..))
import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
import Data.Word (Word16, Word32)
import Foreign.C.Error (throwErrnoIfMinus1)
import Foreign.C.Types
@@ -76,17 +76,14 @@ available = True
data EventQueue = EventQueue {
eqFd :: {-# UNPACK #-} !QueueFd
- , eqChanges :: {-# UNPACK #-} !(MVar (A.Array Event))
, eqEvents :: {-# UNPACK #-} !(A.Array Event)
}
new :: IO E.Backend
new = do
qfd <- kqueue
- changesArr <- A.empty
- changes <- newMVar changesArr
events <- A.new 64
- let !be = E.backend poll modifyFd modifyFdOnce delete (EventQueue qfd changes events)
+ let !be = E.backend poll modifyFd modifyFdOnce delete (EventQueue qfd events)
return be
delete :: EventQueue -> IO ()
@@ -95,12 +92,18 @@ delete q = do
return ()
modifyFd :: EventQueue -> Fd -> E.Event -> E.Event -> IO ()
-modifyFd q fd oevt nevt = withMVar (eqChanges q) $ \ch -> do
- let addChange filt flag = A.snoc ch $ event fd filt flag noteEOF
- when (oevt `E.eventIs` E.evtRead) $ addChange filterRead flagDelete
- when (oevt `E.eventIs` E.evtWrite) $ addChange filterWrite flagDelete
- when (nevt `E.eventIs` E.evtRead) $ addChange filterRead flagAdd
- when (nevt `E.eventIs` E.evtWrite) $ addChange filterWrite flagAdd
+modifyFd q fd oevt nevt
+ | nevt == mempty = do
+ let !ev = event fd (toFilter oevt) flagDelete noteEOF
+ kqueueControl (eqFd q) ev
+ | otherwise = do
+ let !ev = event fd (toFilter nevt) flagAdd noteEOF
+ kqueueControl (eqFd q) ev
+
+toFilter :: E.Event -> Filter
+toFilter evt
+ | evt `E.eventIs` E.evtRead = filterRead
+ | otherwise = filterWrite
modifyFdOnce :: EventQueue -> Fd -> E.Event -> IO ()
modifyFdOnce = error "modifyFdOnce not supported in KQueue backend"
@@ -110,19 +113,13 @@ poll :: EventQueue
-> (Fd -> E.Event -> IO ())
-> IO Int
poll EventQueue{..} mtout f = do
- changesArr <- A.empty
- changes <- swapMVar eqChanges changesArr
- changesLen <- A.length changes
- len <- A.length eqEvents
- when (changesLen > len) $ A.ensureCapacity eqEvents (2 * changesLen)
- n <- A.useAsPtr changes $ \changesPtr chLen ->
- A.unsafeLoad eqEvents $ \evPtr evCap ->
- case mtout of
- Just tout -> withTimeSpec (fromTimeout tout) $
- kevent True eqFd changesPtr chLen evPtr evCap
- Nothing -> withTimeSpec (TimeSpec 0 0) $
- kevent False eqFd changesPtr chLen evPtr evCap
- unless (n == 0) $ do
+ n <- A.unsafeLoad eqEvents $ \evp cap ->
+ case mtout of
+ Just tout -> withTimeSpec (fromTimeout tout) $
+ kevent True eqFd nullPtr 0 evp cap
+ Nothing -> withTimeSpec (TimeSpec 0 0) $
+ kevent False eqFd nullPtr 0 evp cap
+ when (n > 0) $ do
cap <- A.capacity eqEvents
when (n == cap) $ A.ensureCapacity eqEvents (2 * cap)
A.forM_ eqEvents $ \e -> f (fromIntegral (ident e)) (toEvent (filter e))
@@ -269,6 +266,11 @@ instance Storable TimeSpec where
kqueue :: IO QueueFd
kqueue = QueueFd `fmap` throwErrnoIfMinus1 "kqueue" c_kqueue
+kqueueControl :: KQueueFd -> Event -> IO ()
+kqueueControl kfd ev = void $
+ withTimeSpec (TimeSpec 0 0) $ \tp ->
+ withEvent ev $ \evp -> kevent False kfd evp 1 nullPtr 0 tp
+
-- TODO: We cannot retry on EINTR as the timeout would be wrong.
-- Perhaps we should just return without calling any callbacks.
kevent :: Bool -> QueueFd -> Ptr Event -> Int -> Ptr Event -> Int -> Ptr TimeSpec
@@ -332,4 +334,3 @@ foreign import ccall unsafe "kevent"
#endif
#endif /* defined(HAVE_KQUEUE) */
-
More information about the ghc-commits
mailing list