module GHC.Event.Poll
(
new
, available
) where
import Control.Concurrent.MVar (MVar, newMVar, swapMVar)
import Control.Monad ((=<<), liftM, liftM2, unless)
import Data.Bits (Bits, (.|.), (.&.))
import Data.Maybe (Maybe(..))
import Data.Monoid (Monoid(..))
import Foreign.C.Types (CInt(..), CShort(..), CULong(..))
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable(..))
import GHC.Base
import GHC.Conc.Sync (withMVar)
import GHC.Err (undefined)
import GHC.Num (Num(..))
import GHC.Real (ceiling, fromIntegral)
import GHC.Show (Show)
import System.Posix.Types (Fd(..))
import qualified GHC.Event.Array as A
import qualified GHC.Event.Internal as E
available :: Bool
available = True
data Poll = Poll {
pollChanges :: !(MVar (A.Array PollFd))
, pollFd :: !(A.Array PollFd)
}
new :: IO E.Backend
new = E.backend poll modifyFd (\_ -> return ()) `liftM`
liftM2 Poll (newMVar =<< A.empty) A.empty
modifyFd :: Poll -> Fd -> E.Event -> E.Event -> IO ()
modifyFd p fd oevt nevt =
withMVar (pollChanges p) $ \ary ->
A.snoc ary $ PollFd fd (fromEvent nevt) (fromEvent oevt)
reworkFd :: Poll -> PollFd -> IO ()
reworkFd p (PollFd fd npevt opevt) = do
let ary = pollFd p
if opevt == 0
then A.snoc ary $ PollFd fd npevt 0
else do
found <- A.findIndex ((== fd) . pfdFd) ary
case found of
Nothing -> error "reworkFd: event not found"
Just (i,_)
| npevt /= 0 -> A.unsafeWrite ary i $ PollFd fd npevt 0
| otherwise -> A.removeAt ary i
poll :: Poll
-> E.Timeout
-> (Fd -> E.Event -> IO ())
-> IO ()
poll p tout f = do
let a = pollFd p
mods <- swapMVar (pollChanges p) =<< A.empty
A.forM_ mods (reworkFd p)
n <- A.useAsPtr a $ \ptr len -> E.throwErrnoIfMinus1NoRetry "c_poll" $
c_poll ptr (fromIntegral len) (fromIntegral (fromTimeout tout))
unless (n == 0) $ do
A.loop a 0 $ \i e -> do
let r = pfdRevents e
if r /= 0
then do f (pfdFd e) (toEvent r)
let i' = i + 1
return (i', i' == n)
else return (i, True)
fromTimeout :: E.Timeout -> Int
fromTimeout E.Forever = 1
fromTimeout (E.Timeout s) = ceiling $ 1000 * s
data PollFd = PollFd {
pfdFd :: !Fd
, pfdEvents :: !Event
, pfdRevents :: !Event
} deriving (Show)
newtype Event = Event CShort
deriving (Eq, Show, Num, Storable, Bits)
pollIn :: Event
pollIn = Event 1
pollOut :: Event
pollOut = Event 4
pollErr :: Event
pollErr = Event 8
pollHup :: Event
pollHup = Event 16
fromEvent :: E.Event -> Event
fromEvent e = remap E.evtRead pollIn .|.
remap E.evtWrite pollOut
where remap evt to
| e `E.eventIs` evt = to
| otherwise = 0
toEvent :: Event -> E.Event
toEvent e = remap (pollIn .|. pollErr .|. pollHup) E.evtRead `mappend`
remap (pollOut .|. pollErr .|. pollHup) E.evtWrite
where remap evt to
| e .&. evt /= 0 = to
| otherwise = mempty
instance Storable PollFd where
sizeOf _ = (8)
alignment _ = alignment (undefined :: CInt)
peek ptr = do
fd <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
events <- (\hsc_ptr -> peekByteOff hsc_ptr 4) ptr
revents <- (\hsc_ptr -> peekByteOff hsc_ptr 6) ptr
let !pollFd' = PollFd fd events revents
return pollFd'
poke ptr p = do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr (pfdFd p)
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr (pfdEvents p)
(\hsc_ptr -> pokeByteOff hsc_ptr 6) ptr (pfdRevents p)
foreign import ccall safe "poll.h poll"
c_poll :: Ptr PollFd -> CULong -> CInt -> IO CInt