summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Event/Poll.hsc
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/GHC/Event/Poll.hsc')
-rw-r--r--libraries/base/GHC/Event/Poll.hsc24
1 files changed, 23 insertions, 1 deletions
diff --git a/libraries/base/GHC/Event/Poll.hsc b/libraries/base/GHC/Event/Poll.hsc
index 665949b786..6d089fb387 100644
--- a/libraries/base/GHC/Event/Poll.hsc
+++ b/libraries/base/GHC/Event/Poll.hsc
@@ -35,6 +35,7 @@ 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 (ceiling, fromIntegral)
import GHC.Show (Show)
@@ -90,7 +91,7 @@ poll p mtout f = do
E.throwErrnoIfMinus1NoRetry "c_poll" $
case mtout of
Just tout ->
- c_poll ptr (fromIntegral len) (fromIntegral (fromTimeout tout))
+ c_pollLoop ptr (fromIntegral len) (fromTimeout tout)
Nothing ->
c_poll_unsafe ptr (fromIntegral len) 0
unless (n == 0) $ do
@@ -102,6 +103,27 @@ poll p mtout f = do
return (i', i' == n)
else return (i, True)
return (fromIntegral n)
+ where
+ -- The poll timeout is specified as an Int, but c_poll takes a CInt. These
+ -- can't be safely coerced as on many systems (e.g. x86_64) CInt has a a
+ -- maxBound of (2^32 - 1), even though Int may have a significantly higher
+ -- bound.
+ --
+ -- This function deals with timeouts greater than maxBound :: CInt, by
+ -- looping until c_poll returns a non-zero value (0 indicates timeout
+ -- expired) OR the full timeout has passed.
+ c_pollLoop :: Ptr PollFd -> (#type nfds_t) -> Int -> IO CInt
+ c_pollLoop ptr len tout
+ | tout <= maxPollTimeout = 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
+
+ -- Timeout of c_poll is limited by max value of CInt
+ maxPollTimeout :: Int
+ maxPollTimeout = fromIntegral (maxBound :: CInt)
fromTimeout :: E.Timeout -> Int
fromTimeout E.Forever = -1