epoll-0.1: src/System/Linux/EpollM.hs
{-# 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 ()