packages feed

epoll (empty) → 0.1

raw patch · 11 files changed

+771/−0 lines, 11 filesdep +basedep +mtldep +unixsetup-changed

Dependencies added: base, mtl, unix

Files

+ LICENSE view
@@ -0,0 +1,165 @@+		   GNU LESSER GENERAL PUBLIC LICENSE+                       Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.+++  This version of the GNU Lesser General Public License incorporates+the terms and conditions of version 3 of the GNU General Public+License, supplemented by the additional permissions listed below.++  0. Additional Definitions.++  As used herein, "this License" refers to version 3 of the GNU Lesser+General Public License, and the "GNU GPL" refers to version 3 of the GNU+General Public License.++  "The Library" refers to a covered work governed by this License,+other than an Application or a Combined Work as defined below.++  An "Application" is any work that makes use of an interface provided+by the Library, but which is not otherwise based on the Library.+Defining a subclass of a class defined by the Library is deemed a mode+of using an interface provided by the Library.++  A "Combined Work" is a work produced by combining or linking an+Application with the Library.  The particular version of the Library+with which the Combined Work was made is also called the "Linked+Version".++  The "Minimal Corresponding Source" for a Combined Work means the+Corresponding Source for the Combined Work, excluding any source code+for portions of the Combined Work that, considered in isolation, are+based on the Application, and not on the Linked Version.++  The "Corresponding Application Code" for a Combined Work means the+object code and/or source code for the Application, including any data+and utility programs needed for reproducing the Combined Work from the+Application, but excluding the System Libraries of the Combined Work.++  1. Exception to Section 3 of the GNU GPL.++  You may convey a covered work under sections 3 and 4 of this License+without being bound by section 3 of the GNU GPL.++  2. Conveying Modified Versions.++  If you modify a copy of the Library, and, in your modifications, a+facility refers to a function or data to be supplied by an Application+that uses the facility (other than as an argument passed when the+facility is invoked), then you may convey a copy of the modified+version:++   a) under this License, provided that you make a good faith effort to+   ensure that, in the event an Application does not supply the+   function or data, the facility still operates, and performs+   whatever part of its purpose remains meaningful, or++   b) under the GNU GPL, with none of the additional permissions of+   this License applicable to that copy.++  3. Object Code Incorporating Material from Library Header Files.++  The object code form of an Application may incorporate material from+a header file that is part of the Library.  You may convey such object+code under terms of your choice, provided that, if the incorporated+material is not limited to numerical parameters, data structure+layouts and accessors, or small macros, inline functions and templates+(ten or fewer lines in length), you do both of the following:++   a) Give prominent notice with each copy of the object code that the+   Library is used in it and that the Library and its use are+   covered by this License.++   b) Accompany the object code with a copy of the GNU GPL and this license+   document.++  4. Combined Works.++  You may convey a Combined Work under terms of your choice that,+taken together, effectively do not restrict modification of the+portions of the Library contained in the Combined Work and reverse+engineering for debugging such modifications, if you also do each of+the following:++   a) Give prominent notice with each copy of the Combined Work that+   the Library is used in it and that the Library and its use are+   covered by this License.++   b) Accompany the Combined Work with a copy of the GNU GPL and this license+   document.++   c) For a Combined Work that displays copyright notices during+   execution, include the copyright notice for the Library among+   these notices, as well as a reference directing the user to the+   copies of the GNU GPL and this license document.++   d) Do one of the following:++       0) Convey the Minimal Corresponding Source under the terms of this+       License, and the Corresponding Application Code in a form+       suitable for, and under terms that permit, the user to+       recombine or relink the Application with a modified version of+       the Linked Version to produce a modified Combined Work, in the+       manner specified by section 6 of the GNU GPL for conveying+       Corresponding Source.++       1) Use a suitable shared library mechanism for linking with the+       Library.  A suitable mechanism is one that (a) uses at run time+       a copy of the Library already present on the user's computer+       system, and (b) will operate properly with a modified version+       of the Library that is interface-compatible with the Linked+       Version.++   e) Provide Installation Information, but only if you would otherwise+   be required to provide such information under section 6 of the+   GNU GPL, and only to the extent that such information is+   necessary to install and execute a modified version of the+   Combined Work produced by recombining or relinking the+   Application with a modified version of the Linked Version. (If+   you use option 4d0, the Installation Information must accompany+   the Minimal Corresponding Source and Corresponding Application+   Code. If you use option 4d1, you must provide the Installation+   Information in the manner specified by section 6 of the GNU GPL+   for conveying Corresponding Source.)++  5. Combined Libraries.++  You may place library facilities that are a work based on the+Library side by side in a single library together with other library+facilities that are not Applications and are not covered by this+License, and convey such a combined library under terms of your+choice, if you do both of the following:++   a) Accompany the combined library with a copy of the same work based+   on the Library, uncombined with any other library facilities,+   conveyed under the terms of this License.++   b) Give prominent notice with the combined library that part of it+   is a work based on the Library, and explaining where to find the+   accompanying uncombined form of the same work.++  6. Revised Versions of the GNU Lesser General Public License.++  The Free Software Foundation may publish revised and/or new versions+of the GNU Lesser General Public License from time to time. Such new+versions will be similar in spirit to the present version, but may+differ in detail to address new problems or concerns.++  Each version is given a distinguishing version number. If the+Library as you received it specifies that a certain numbered version+of the GNU Lesser General Public License "or any later version"+applies to it, you have the option of following the terms and+conditions either of that published version or of any later version+published by the Free Software Foundation. If the Library as you+received it does not specify a version number of the GNU Lesser+General Public License, you may choose any version of the GNU Lesser+General Public License ever published by the Free Software Foundation.++  If the Library as you received it specifies that a proxy can decide+whether future versions of the GNU Lesser General Public License shall+apply, that proxy's public statement of acceptance of any version is+permanent authorization for you to choose that version for the+Library.
+ README view
@@ -0,0 +1,7 @@+This is a low-level Haskell FFI interface to epoll, a Linux specific I/O+notification facility. For usage examples please have a look into the +examples directory (please compile with -threaded option). ++This library has been developed and tested with GHC 6.10.4 and +Linux 2.6.28-15 (x86).+
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main where++import Distribution.Simple++main = defaultMain+
+ epoll.cabal view
@@ -0,0 +1,27 @@+name:               epoll+version:            0.1+synopsis:           Low-level bindings to epoll.+description:        Bindings to epoll, a Linux specific I/O+                    event notication facility (cf. man epoll(7)).+category:           sys+license:            LGPL+license-file:       LICENSE+author:             Toralf Wittner+maintainer:         toralf.wittner@gmail.com+copyright:          Copyright (c) 2009 Toralf Wittner+stability:          experimental+tested-With:        GHC == 6.10.4+cabal-version:      >= 1.6.0+build-type:         Simple+extra-source-files: README, examples/*.hs++library+  exposed-modules:  System.Linux.Epoll,+                    System.Linux.EpollM,+                    System.Linux.Epoll.Base+  other-modules:    Util+  ghc-options:      -Wall -O2+  extensions:       CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving+  build-depends:    base >= 3 && < 5, unix, mtl+  hs-source-dirs:   src+
+ examples/Server.hs view
@@ -0,0 +1,77 @@+module Main where++import System.Linux.EpollM+import System.Posix.IO+import System.Posix.Types+import System.Environment+import System.IO+import Data.Maybe+import Text.Printf+import Control.Monad+import Control.Monad.Trans+import System.Posix.Signals+import Network.Socket++main :: IO ()+main = getAndVerifyArgs >>= start . head++start :: String -> IO ()+start p = runEpollBig_ $ do++    defaultDispatchLoop_ readRequest++    ai <- liftIO $ getAddrInfo (Just (defaultHints {addrFlags = [AI_PASSIVE]}))+                               Nothing +                               (Just p)++    let serveraddr = head ai++    -- create server socket+    sock <- liftIO $ socket (addrFamily serveraddr) Stream defaultProtocol+    liftIO $ setSocketOption sock ReuseAddr 1++    -- bind it to the address we're listening to+    liftIO $ bindSocket sock (addrAddress serveraddr)++    liftIO $ printf "Listening at port %s\n" p++    -- start listening for connection requests max. connection requests waiting+    -- to be accepted = 5 (max. queue size)+    liftIO $ listen sock 256++    -- Ignore broken pipes+    liftIO $ installHandler sigPIPE Ignore Nothing++    -- accept connection requests (CTRL-C to abort)+    forever $ do+        (connsock, clientaddr) <- liftIO $ accept sock+        procRequest connsock clientaddr+ where+    procRequest :: Socket -> SockAddr -> Epoll ()+    procRequest sock' _ = do+        let fd = Fd $ fdSocket sock'+        liftIO $ setFdOption fd NonBlockingRead True+        add sock' [inEvent, peerCloseEvent, oneShotEvent] fd+        return ()++readRequest :: Event Socket -> Epoll ()+readRequest e = fork_ $ do+    let et = eventType e+        fd = eventFd e+    liftIO $ printf "event=%s, fd=%s\n" (show et) (show fd)+    if et =~ peerCloseEvent+        then do liftIO $ putStrLn "peer closed"+                delete (eventDesc e)+                liftIO $ sClose (eventRef e)+        else do (s, _) <- liftIO $ fdRead fd 2048+                modify [inEvent, peerCloseEvent, oneShotEvent] (eventDesc e)+                liftIO $ printf "readRequest: %s\n" s++getAndVerifyArgs :: IO [String]+getAndVerifyArgs = do+    args <- getArgs+    when (length args /= 1)+         (error "Usage: Server <port>")+    return args++
+ examples/Stdin.hs view
@@ -0,0 +1,28 @@+module Main where++import System.Linux.Epoll+import System.Posix.IO+import System.IO+import Data.Maybe+import Text.Printf++eventTypes :: [EventType]+eventTypes = [inEvent, edgeTriggeredEvent, oneShotEvent]++callback :: Device -> Event a -> IO ()+callback d e = do+    let et = eventType e+        fd = eventFd e+    setFdOption fd NonBlockingRead True+    printf "event=%s, fd=%s\n" (show et) (show fd)+    (s, c) <- fdRead fd 16+    printf "read %s byte(s): %s\n" (show c) s+    modify d eventTypes (eventDesc e)++main :: IO ()+main = do+    let s = fromJust $ toSize 32+    dev <- create s+    add dev () eventTypes stdInput+    defaultDispatchLoop (callback dev) dev+
+ examples/StdinM.hs view
@@ -0,0 +1,28 @@+module Main where++import Text.Printf+import Control.Monad.Reader+import System.IO+import System.Posix.IO+import System.Linux.EpollM++eventTypes :: [EventType]+eventTypes = [inEvent, edgeTriggeredEvent, oneShotEvent]++callback :: Event a -> Epoll ()+callback e = do+    let fd = eventFd e+        et = eventType e+        ds = eventDesc e+    liftIO $ do+        setFdOption fd NonBlockingRead True+        printf "event=%s, fd=%s\n" (show et) (show fd)+        (s, c) <- fdRead fd 16+        printf "read %s byte(s): %s\n" (show c) s+    modify eventTypes ds++main :: IO ()+main = runEpollSmall_ $ do+    add_ eventTypes stdInput+    defaultDispatchLoop callback+
+ src/System/Linux/Epoll.hs view
@@ -0,0 +1,29 @@+-- |+-- Module      : System.Linux.Epoll+-- Copyright   : (c) 2009 Toralf Wittner+-- License     : LGPL+-- Maintainer  : toralf.wittner@gmail.com+-- Stability   : experimental+-- Portability : non-portable++module System.Linux.Epoll (+    module System.Linux.Epoll.Base,++    dispatchLoop,+    defaultDispatchLoop++) where++import Data.Maybe+import Control.Monad+import System.Linux.Epoll.Base++-- | Repeatedly waits for epoll events and invokes the given callback function+-- with each event occured.+dispatchLoop :: Duration -> (Event a -> IO ()) -> Device -> IO ()+dispatchLoop dur f dev = forever $ wait dur dev >>= mapM_ (\e -> f e)++-- | Like 'dispatchLoop' but uses a default 'Duration' of 500ms.+defaultDispatchLoop :: (Event a -> IO ()) -> Device -> IO ()+defaultDispatchLoop = dispatchLoop (fromJust $ toDuration 500)+
+ src/System/Linux/Epoll/Base.hsc view
@@ -0,0 +1,235 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+-- |+-- Module      : System.Linux.Epoll.Base+-- Copyright   : (c) 2009 Toralf Wittner+-- License     : LGPL+-- Maintainer  : toralf.wittner@gmail.com+-- Stability   : experimental+-- Portability : non-portable+-- +-- Low level interface to Linux' epoll, a high performance polling mechanism+-- which handles high numbers of file descriptors efficiently. See man epoll(7)+-- for details.++module System.Linux.Epoll.Base (++    EventType,+    Size,+    toSize,+    Duration,+    toDuration,+    Descriptor,+    Device,+    Event (eventFd, eventType, eventRef, eventDesc),+    (=~),++    create,+    close,+    wait,++    add,+    modify,+    delete,++    inEvent,+    outEvent,+    peerCloseEvent,+    urgentEvent,+    errorEvent,+    hangupEvent,+    edgeTriggeredEvent,+    oneShotEvent++) where++import Util+import Foreign+import Foreign.C.Types (CInt)+import Foreign.C.Error (throwErrnoIfMinus1,+                        throwErrnoIfMinus1_,+                        throwErrnoIfMinus1Retry)+import Foreign.Marshal.Array (peekArray, mallocArray)+import Foreign.Marshal.Utils (with)+import System.Posix.Types (Fd (Fd))+import System.Posix.Signals (installHandler, sigPIPE, Handler (Ignore))++#include <sys/epoll.h>++-- | EventType corresponds to epoll's event type defines, e.g. EPOLLIN,+-- EPOLLOUT, EPOLLET, etc.+newtype EventType = EventType { fromEventType :: Int } deriving (Eq, Ord)++-- | Operation corresponds to epoll's EPOLL_CTL_ADD et al. It is the operation+-- designation in epoll_ctl.+newtype Operation = Operation { fromOp :: Int } deriving (Eq, Ord)++-- | Unsigned type used for length specifications.+newtype Size = Size { fromSize :: Word32 } deriving (Eq, Ord, Show)++-- | Unsigned type used for timeout specifications.+newtype Duration = Duration { fromDuration :: Word32 } deriving (Eq, Ord, Show)++-- | Event descriptor. Will be returned from 'add' and must be passed to+-- 'delete' exactly once.+newtype Descriptor a = Descriptor { descrPtr :: StablePtr (Fd, a) }++-- | Abstract epoll device. Holds internal data. Returned from 'create' and used+-- in almost every other API function. Must be closed explicitely with 'close'.+data Device = Device {+        deviceFd      :: !Fd,                -- ^ The epoll file descriptor.+        eventArray    :: !(Ptr EventStruct), -- ^ The event array used in 'wait'.+        eventArrayLen :: !Size               -- ^ The size of the event array.+    } deriving (Eq, Show)++-- | A single event ocurrence.+data Event a = Event {+        eventFd   :: !Fd,        -- ^ The file descriptor.+        eventType :: !EventType, -- ^ The event type.+        eventRef  :: !a,         -- ^ The user data as given in 'add'.+        eventDesc :: !(Descriptor a)+    }++-- | Representation of struct epoll_event.+data EventStruct = EventStruct {+        epollEvents :: !Word32,+        epollData   :: !(Ptr ())+    }++instance Storable EventStruct where+    alignment _ = #{alignment struct epoll_event}+    sizeOf _ = #{size struct epoll_event}+    peek p = do+        evts <- #{peek struct epoll_event, events} p+        dat  <- #{peek struct epoll_event, data} p+        return (EventStruct evts dat)+    poke p (EventStruct evts dat) = do+        #{poke struct epoll_event, events} p evts+        #{poke struct epoll_event, data} p dat++#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)++#{enum EventType, EventType,+    inEvent = EPOLLIN,+    outEvent = EPOLLOUT,+    peerCloseEvent = EPOLLRDHUP,+    urgentEvent = EPOLLPRI,+    errorEvent = EPOLLERR,+    hangupEvent = EPOLLHUP,+    edgeTriggeredEvent = EPOLLET,+    oneShotEvent = EPOLLONESHOT+}++instance Show EventType where+    show e | e == inEvent = "EPOLLIN"+           | e == outEvent = "EPOLLOUT"+           | e == peerCloseEvent = "EPOLLRDHUP"+           | e == urgentEvent = "EPOLLPRI"+           | e == errorEvent = "EPOLLERR"+           | e == hangupEvent = "EPOLLHUP"+           | e == edgeTriggeredEvent = "EPOLLET"+           | e == oneShotEvent = "EPOLLONESHOT"+           | otherwise = show $ fromEventType e++#{enum Operation, Operation,+    addOp = EPOLL_CTL_ADD,+    modifyOp = EPOLL_CTL_MOD,+    deleteOp = EPOLL_CTL_DEL+}++instance Show Operation where+    show op | op == addOp    = "EPOLL_CTL_ADD"+            | op == modifyOp = "EPOLL_CTL_MOD"+            | op == deleteOp = "EPOLL_CTL_DEL"+            | otherwise = show $ fromOp op++-- | Creates an epoll device. Must be closed with 'close'.+-- The parameter 'Size' specifies the number of events that can be reported by a+-- single call to 'wait'.+create :: Size -> IO Device+create s = do+    dev <- throwErrnoIfMinus1 "create: c_epoll_create" (c_epoll_create 0)+    buf <- mallocArray (fromIntegral $ fromSize s)+    installHandler sigPIPE Ignore Nothing+    return $ Device (Fd dev) buf s++-- | Closes epoll device.+close :: Device -> IO ()+close = free . eventArray++-- | Adds a filedescriptor to the epoll watch set using the specified+-- EventTypes. User data might be passed in as well which will be returned on+-- event occurence as part of the 'Event' type. Returns an event descriptor+-- which must be deleted from the watch set with 'delete'.+add :: Device -> a -> [EventType] -> Fd -> IO (Descriptor a)+add dev dat evts fd = do+    p <- newStablePtr (fd, dat)+    control dev addOp evts p+    return $ Descriptor p++-- | Modified the event types of the event descriptor.+modify :: Device -> [EventType] -> Descriptor a -> IO ()+modify dev evts des = control dev modifyOp evts (descrPtr des)++-- | Removes the event descriptor from the epoll watch set.+delete :: Device -> Descriptor a -> IO ()+delete dev des = do+    control dev deleteOp [] (descrPtr des)+    freeStablePtr (descrPtr des)++-- | Representation of epoll_ctl.+control :: Device -> Operation -> [EventType] -> StablePtr (Fd, a) -> IO ()+control dev op evts ptr = do+    (fd, _) <- deRefStablePtr ptr+    throwErrnoIfMinus1_ ("control: c_epoll_ctl (" ++ (show op) ++ ")")+        (with (EventStruct (fromIntegral . fromEventType $ combEvents evts)+                           (castStablePtrToPtr ptr))+            (c_epoll_ctl (intToNum $ deviceFd dev)+                         (fromIntegral $ fromOp op)+                         (intToNum fd)))++-- | Waits for the specified duration on all event descriptors. Returns the+-- list of events that occured.+wait :: Duration -> Device -> IO [Event a]+wait timeout dev = do+    r <- throwErrnoIfMinus1Retry "wait: c_epoll_wait"+         (c_epoll_wait (intToNum $ deviceFd dev)+                       (eventArray dev)+                       (fromIntegral . fromSize $ eventArrayLen dev)+                       (fromIntegral $ fromDuration timeout))+    evts <- peekArray (fromIntegral r) (eventArray dev)+    mapM createEvent evts+ where+     createEvent e = do+        let ptr = castPtrToStablePtr $ epollData e+            ety = EventType (fromIntegral $ epollEvents e)+        (fd, ref) <- deRefStablePtr ptr+        return (Event fd ety ref (Descriptor ptr))++-- | Match operator. Useful to test whether an 'EventType' returned from+-- 'wait' contains one of the defined event types because EventTypes returned by+-- wait might be the bitwise OR of several EventTypes.+(=~) :: EventType -> EventType -> Bool+e1 =~ e2 = fromEventType e1 .&. fromEventType e2 /= 0++infix 4 =~++toSize :: Int -> Maybe Size+toSize i = toWord32 i >>= Just . Size++toDuration :: Int -> Maybe Duration+toDuration i = toWord32 i >>= Just . Duration++combEvents :: [EventType] -> EventType+combEvents = EventType . foldr ((.|.) . fromEventType) 0++-- Foreign Imports --++foreign import ccall unsafe "epoll.h epoll_create"+    c_epoll_create :: CInt -> IO CInt++foreign import ccall unsafe "epoll.h epoll_ctl"+    c_epoll_ctl :: CInt -> CInt -> CInt -> Ptr EventStruct -> IO CInt++foreign import ccall safe "epoll.h epoll_wait"+    c_epoll_wait :: CInt -> Ptr EventStruct -> CInt -> CInt -> IO CInt+
+ src/System/Linux/EpollM.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- |+-- Module      : System.Linux.EpollM+-- Copyright   : (c) 2009 Toralf Wittner+-- License     : LGPL+-- Maintainer  : toralf.wittner@gmail.com+-- Stability   : experimental+-- Portability : non-portable+--+-- Monadic epoll interface. Similar to System.Linux.Epoll.Base but uses+-- 'ReaderT' to hold a 'Device' instead of passing it to many functions.++module System.Linux.EpollM (++    Epoll,+    runEpoll,+    runEpoll_,+    runEpollSmall_,+    runEpollMed_,+    runEpollBig_,+    add,+    add_,+    modify,+    delete,+    wait,+    wait_,+    device,+    dispatchLoop,+    dispatchLoop_,+    defaultDispatchLoop,+    defaultDispatchLoop_,+    fork,+    fork_,++    E.EventType,+    E.Size,+    E.toSize,+    E.Duration,+    E.toDuration,+    E.Descriptor,+    E.Device,+    E.Event (eventFd, eventType, eventRef, eventDesc),+    (E.=~),++    E.create,+    E.close,++    E.inEvent,+    E.outEvent,+    E.peerCloseEvent,+    E.urgentEvent,+    E.errorEvent,+    E.hangupEvent,+    E.edgeTriggeredEvent,+    E.oneShotEvent++) where++import Data.Maybe (fromJust)+import Control.Concurrent+import Control.Monad.Reader+import Control.Exception (bracket)+import System.Posix.Types (Fd)+import qualified System.Linux.Epoll as E++newtype Epoll a = Epoll {+        runDev :: ReaderT E.Device IO a+    } deriving (Monad, MonadIO, MonadReader E.Device) ++-- | Run Epoll monad.+runEpoll :: E.Device -> Epoll a -> IO a+runEpoll d e = runReaderT (runDev e) d++-- | Run Epoll monad. Like 'runEpoll' but creates and closes+-- 'Device' implcitely.+runEpoll_ :: E.Size -> Epoll a -> IO a+runEpoll_ s e = bracket (E.create s) E.close (flip runEpoll e)++-- | Like 'runEpoll_' but with an implicit 'Size' value of 8.+runEpollSmall_ :: Epoll a -> IO a+runEpollSmall_ = runEpollN_ 8++-- | Like 'runEpoll_' but with an implicit 'Size' value of 256.+runEpollMed_ :: Epoll a -> IO a+runEpollMed_ = runEpollN_ 256++-- | Like 'runEpoll_' but with an implicit 'Size' value of 8192.+runEpollBig_ :: Epoll a -> IO a+runEpollBig_ = runEpollN_ 8192++-- | Adds the given file descriptor with the specified event types to epoll.+add :: a -> [E.EventType] -> Fd -> Epoll (E.Descriptor a)+add d e f = do+    dev <- ask+    des <- liftIO $ E.add dev d e f+    return des++-- | Like 'add' but without accepting custom data.+add_ :: [E.EventType] -> Fd -> Epoll (E.Descriptor ())+add_ = add () ++-- | Modify the event type set of the given descriptor.+modify :: [E.EventType] -> E.Descriptor a -> Epoll ()+modify e d = do+    dev <- ask+    liftIO $ E.modify dev e d++-- | Deletes the descriptor from epoll.+delete :: E.Descriptor a -> Epoll ()+delete d = do+    dev <- ask+    liftIO $ E.delete dev d++-- | Waits up to the given duration for events on all descriptors.+wait :: E.Duration -> Epoll [E.Event a]+wait d = do+    dev <- ask+    liftIO $ E.wait d dev++-- | Like 'wait' but uses a 'Duration' of 500ms.+wait_ :: Epoll [E.Event a]+wait_ = wait (fromJust $ E.toDuration 500)++runEpollN_ :: Int -> Epoll a -> IO a+runEpollN_ = runEpoll_ . fromJust . E.toSize++device :: Epoll E.Device+device = ask++-- | Waits for events and calls the given function for each.+dispatchLoop :: E.Duration -> (E.Event a -> Epoll ()) -> Epoll ()+dispatchLoop dur f = forever $ wait dur >>= mapM_ f++-- | Like 'dispatchLoop' but with predefined 'Duration' of 500ms.+defaultDispatchLoop :: (E.Event a -> Epoll ()) -> Epoll ()+defaultDispatchLoop = dispatchLoop (fromJust $ E.toDuration 500)++-- | Like 'dispatchLoop' but forks itself into another thread+dispatchLoop_ :: E.Duration -> (E.Event a -> Epoll ()) -> Epoll ThreadId+dispatchLoop_ dur f = fork $ forever $ wait dur >>= mapM_ f++-- | Like 'defaultDispatchLoop' but forks itself into another thread+defaultDispatchLoop_ :: (E.Event a -> Epoll ()) -> Epoll ThreadId+defaultDispatchLoop_ = dispatchLoop_ (fromJust $ E.toDuration 500)++-- | Uses 'forkIO' to spark an epoll computation into another thread.+fork :: Epoll () -> Epoll ThreadId+fork (Epoll r) = Epoll $ mapReaderT forkIO r++-- | Like 'fork' but swallows the ThreadId.+fork_ :: Epoll () -> Epoll ()+fork_ e = fork e >> return ()+
+ src/Util.hs view
@@ -0,0 +1,15 @@+module Util (intToNum, toWord32, forkIO_) where++import Data.Word+import Control.Concurrent (forkIO)++intToNum :: (Integral a, Num b) => a -> b+intToNum = fromIntegral . toInteger++toWord32 :: Int -> Maybe Word32+toWord32 i | i < 0     = Nothing+           | otherwise = Just (fromIntegral i)++forkIO_ :: IO () -> IO ()+forkIO_ act = forkIO act >> return ()+