@@ -13,7 +13,6 @@ module Network.Wai.Handler.Warp.Run where
1313import Control.Applicative ((<$>))
1414#endif
1515import Control.Arrow (first)
16−import Control.Concurrent (threadDelay)
1716import qualified Control.Concurrent as Conc (yield)
1817import Control.Exception as E
1918import Control.Monad (when, unless, void)
@@ -23,6 +22,8 @@ import Data.Char (chr)
2322import "iproute" Data.IP (toHostAddress, toHostAddress6)
2423import Data.IORef (IORef, newIORef, readIORef, writeIORef)
2524import Data.Streaming.Network (bindPortTCP)
25+import Foreign.C.Error (Errno(..), eCONNABORTED)
26+import GHC.IO.Exception (IOException(..))
2627import Network (sClose, Socket)
2728import Network.Socket (accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6), setSocketOption, SocketOption(..))
2829import qualified Network.Socket.ByteString as Sock
@@ -44,7 +45,7 @@ import qualified Network.Wai.Handler.Warp.Timeout as T
4445import Network.Wai.Handler.Warp.Types
4546import Network.Wai.Internal (ResponseReceived (ResponseReceived))
4647import System.Environment (getEnvironment)
47−import System.IO.Error (isFullErrorType, ioeGetErrorType)
48+import System.Timeout (timeout)
4849
4950#if WINDOWS
5051import Network.Wai.Handler.Warp.Windows
@@ -218,7 +219,7 @@ acceptConnection set getConnMaker app counter ii0 = do
218219 -- ensure that no async exception is throw between the call to
219220 -- acceptNewConnection and the registering of connClose.
220221 void $ mask_ acceptLoop
221− gracefulShutdown counter
222+ gracefulShutdown set counter
222223 where
223224 acceptLoop = do
224225 -- Allow async exceptions before receiving the next connection maker.
@@ -242,17 +243,14 @@ acceptConnection set getConnMaker app counter ii0 = do
242243 ex <- try getConnMaker
243244 case ex of
244245 Right x -> return $ Just x
245− Left e -> do
246− settingsOnException set Nothing $ toException e
247− if isFullErrorType (ioeGetErrorType e) then do
248− -- "resource exhausted (Too many open files)" may
249− -- happen by accept(). Wait a second hoping that
250− -- resource will be available.
251− threadDelay 1000000
252− acceptNewConnection
253− else
254− -- Assuming the listen socket is closed.
255− return Nothing
246+ Left e -> do
247+ let eConnAborted = getErrno eCONNABORTED
248+ getErrno (Errno cInt) = cInt
249+ if ioe_errno e == Just eConnAborted
250+ then acceptNewConnection
251+ else do
252+ settingsOnException set Nothing $ toException e
253+ return Nothing
256254
257255-- Fork a new worker thread for this connection maker, and ask for a
258256-- function to unmask (i.e., allow async exceptions to be thrown).
@@ -498,5 +496,11 @@ setSocketCloseOnExec _ = return ()
498496setSocketCloseOnExec socket = F.setFileCloseOnExec $ fromIntegral $ fdSocket socket
499497#endif
500498
501−gracefulShutdown :: Counter -> IO ()
502−gracefulShutdown counter = waitForZero counter
499+gracefulShutdown :: Settings -> Counter -> IO ()
500+gracefulShutdown set counter =
501+ case settingsGracefulShutdownTimeout set of
502+ Nothing ->
503+ waitForZero counter
504+ (Just seconds) ->
505+ void (timeout (seconds * microsPerSecond) (waitForZero counter))
506+ where microsPerSecond = 1000000