{-# LINE 1 "libraries/base/GHC/Event/Poll.hsc" #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE GeneralizedNewtypeDeriving
, NoImplicitPrelude
, BangPatterns
#-}
module GHC.Event.Poll
(
new
, available
) where
{-# LINE 26 "libraries/base/GHC/Event/Poll.hsc" #-}
import Control.Concurrent.MVar (MVar, newMVar, swapMVar)
import Data.Bits (Bits, FiniteBits, (.|.), (.&.))
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(..), CNfds(..))
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) $
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 -> CNfds -> Int -> IO CInt
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
)
pollIn :: Event
pollIn = Event 1
pollOut :: Event
pollOut = Event 4
pollErr :: Event
pollErr = Event 8
pollHup :: Event
pollHup = Event 16
{-# LINE 170 "libraries/base/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 188 "libraries/base/GHC/Event/Poll.hsc" #-}
alignment _ = alignment (undefined :: CInt)
peek ptr = do
fd <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 192 "libraries/base/GHC/Event/Poll.hsc" #-}
events <- (\hsc_ptr -> peekByteOff hsc_ptr 4) ptr
{-# LINE 193 "libraries/base/GHC/Event/Poll.hsc" #-}
revents <- (\hsc_ptr -> peekByteOff hsc_ptr 6) ptr
{-# LINE 194 "libraries/base/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 199 "libraries/base/GHC/Event/Poll.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr (pfdEvents p)
{-# LINE 200 "libraries/base/GHC/Event/Poll.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 6) ptr (pfdRevents p)
{-# LINE 201 "libraries/base/GHC/Event/Poll.hsc" #-}
foreign import ccall safe "poll.h poll"
c_poll :: Ptr PollFd -> CNfds -> CInt -> IO CInt
foreign import ccall unsafe "poll.h poll"
c_poll_unsafe :: Ptr PollFd -> CNfds -> CInt -> IO CInt
{-# LINE 208 "libraries/base/GHC/Event/Poll.hsc" #-}