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 +165/−0
- README +7/−0
- Setup.hs +6/−0
- epoll.cabal +27/−0
- examples/Server.hs +77/−0
- examples/Stdin.hs +28/−0
- examples/StdinM.hs +28/−0
- src/System/Linux/Epoll.hs +29/−0
- src/System/Linux/Epoll/Base.hsc +235/−0
- src/System/Linux/EpollM.hs +154/−0
- src/Util.hs +15/−0
+ 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 ()+