{-# LINE 1 "GHC/Event/Poll.hsc" #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE GeneralizedNewtypeDeriving
, NoImplicitPrelude
, BangPatterns
#-}
module GHC.Event.Poll
(
new
, available
) where
{-# LINE 26 "GHC/Event/Poll.hsc" #-}
import Control.Concurrent.MVar (MVar, newMVar, swapMVar)
import Data.Bits (Bits, FiniteBits, (.|.), (.&.))
import Data.Word
import Foreign.C.Types (CInt(..), CShort(..))
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable(..))
import GHC.Base
import GHC.Conc.Sync (withMVar)
import GHC.Enum (maxBound)
import GHC.Num (Num(..))
import GHC.Real (fromIntegral, div)
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
{-# INLINE available #-}
data Poll = Poll {
pollChanges :: {-# UNPACK #-} !(MVar (A.Array PollFd))
, pollFd :: {-# UNPACK #-} !(A.Array PollFd)
}
new :: IO E.Backend
new = E.backend poll modifyFd modifyFdOnce (\_ -> return ()) `liftM`
liftM2 Poll (newMVar =<< A.empty) A.empty
modifyFd :: Poll -> Fd -> E.Event -> E.Event -> IO Bool
modifyFd p fd oevt nevt =
withMVar (pollChanges p) $ \ary -> do
A.snoc ary $ PollFd fd (fromEvent nevt) (fromEvent oevt)
return True
modifyFdOnce :: Poll -> Fd -> E.Event -> IO Bool
modifyFdOnce = errorWithoutStackTrace "modifyFdOnce not supported in Poll backend"
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 -> errorWithoutStackTrace "reworkFd: event not found"
Just (i,_)
| npevt /= 0 -> A.unsafeWrite ary i $ PollFd fd npevt 0
| otherwise -> A.removeAt ary i
poll :: Poll
-> Maybe E.Timeout
-> (Fd -> E.Event -> IO ())
-> IO Int
poll p mtout 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" $
case mtout of
Just tout ->
c_pollLoop ptr (fromIntegral len) (fromTimeout tout)
Nothing ->
c_poll_unsafe ptr (fromIntegral len) 0
when (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)
return (fromIntegral n)
where
c_pollLoop :: Ptr PollFd -> (Word64) -> Int -> IO CInt
{-# LINE 114 "GHC/Event/Poll.hsc" #-}
c_pollLoop ptr len tout
| isShortTimeout = c_poll ptr len (fromIntegral tout)
| otherwise = do
result <- c_poll ptr len (fromIntegral maxPollTimeout)
if result == 0
then c_pollLoop ptr len (fromIntegral (tout - maxPollTimeout))
else return result
where
isShortTimeout = tout <= maxPollTimeout || maxPollTimeout < 0
maxPollTimeout :: Int
maxPollTimeout = fromIntegral (maxBound :: CInt)
fromTimeout :: E.Timeout -> Int
fromTimeout E.Forever = -1
fromTimeout (E.Timeout s) = fromIntegral $ s `divRoundUp` 1000000
where
divRoundUp num denom = (num + denom - 1) `div` denom
data PollFd = PollFd {
pfdFd :: {-# UNPACK #-} !Fd
, pfdEvents :: {-# UNPACK #-} !Event
, pfdRevents :: {-# UNPACK #-} !Event
} deriving Show
newtype Event = Event CShort
deriving ( Eq
, Show
, Num
, Storable
, Bits
, FiniteBits
)
{-# LINE 176 "GHC/Event/Poll.hsc" #-}
pollIn :: Event
pollIn = Event 1
pollOut :: Event
pollOut = Event 4
pollErr :: Event
pollErr = Event 8
pollHup :: Event
pollHup = Event 16
{-# LINE 182 "GHC/Event/Poll.hsc" #-}
{-# LINE 183 "GHC/Event/Poll.hsc" #-}
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)
{-# LINE 201 "GHC/Event/Poll.hsc" #-}
alignment _ = alignment (undefined :: CInt)
peek ptr = do
fd <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 205 "GHC/Event/Poll.hsc" #-}
events <- (\hsc_ptr -> peekByteOff hsc_ptr 4) ptr
{-# LINE 206 "GHC/Event/Poll.hsc" #-}
revents <- (\hsc_ptr -> peekByteOff hsc_ptr 6) ptr
{-# LINE 207 "GHC/Event/Poll.hsc" #-}
let !pollFd' = PollFd fd events revents
return pollFd'
poke ptr p = do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr (pfdFd p)
{-# LINE 212 "GHC/Event/Poll.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr (pfdEvents p)
{-# LINE 213 "GHC/Event/Poll.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 6) ptr (pfdRevents p)
{-# LINE 214 "GHC/Event/Poll.hsc" #-}
foreign import ccall safe "poll.h poll"
c_poll :: Ptr PollFd -> (Word64) -> CInt -> IO CInt
{-# LINE 217 "GHC/Event/Poll.hsc" #-}
foreign import ccall unsafe "poll.h poll"
c_poll_unsafe :: Ptr PollFd -> (Word64) -> CInt -> IO CInt
{-# LINE 220 "GHC/Event/Poll.hsc" #-}
{-# LINE 221 "GHC/Event/Poll.hsc" #-}