@@ -13,7 +13,6 @@ module Network.Wai.Handler.Warp.Run where
13import Control.Applicative ((<$>))
13import Control.Applicative ((<$>))
15import Control.Arrow (first)
15import Control.Arrow (first)
16−import Control.Concurrent (threadDelay)
17import qualified Control.Concurrent as Conc (yield)
16import qualified Control.Concurrent as Conc (yield)
18import Control.Exception as E
17import Control.Exception as E
19import Control.Monad (when, unless, void)
18import Control.Monad (when, unless, void)
@@ -23,6 +22,8 @@ import Data.Char (chr)
23import "iproute" Data.IP (toHostAddress, toHostAddress6)
22import "iproute" Data.IP (toHostAddress, toHostAddress6)
24import Data.IORef (IORef, newIORef, readIORef, writeIORef)
23import Data.IORef (IORef, newIORef, readIORef, writeIORef)
25import Data.Streaming.Network (bindPortTCP)
24import Data.Streaming.Network (bindPortTCP)
25+import Foreign.C.Error (Errno(..), eCONNABORTED)
26+import GHC.IO.Exception (IOException(..))
26import Network (sClose, Socket)
27import Network (sClose, Socket)
27import Network.Socket (accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6), setSocketOption, SocketOption(..))
28import Network.Socket (accept, withSocketsDo, SockAddr(SockAddrInet, SockAddrInet6), setSocketOption, SocketOption(..))
28import qualified Network.Socket.ByteString as Sock
29import qualified Network.Socket.ByteString as Sock
@@ -44,7 +45,7 @@ import qualified Network.Wai.Handler.Warp.Timeout as T
44import Network.Wai.Handler.Warp.Types
45import Network.Wai.Handler.Warp.Types
45import Network.Wai.Internal (ResponseReceived (ResponseReceived))
46import Network.Wai.Internal (ResponseReceived (ResponseReceived))
46import System.Environment (getEnvironment)
47import System.Environment (getEnvironment)
47−import System.IO.Error (isFullErrorType, ioeGetErrorType)
48+import System.Timeout (timeout)
49#if WINDOWS
50#if WINDOWS
50import Network.Wai.Handler.Warp.Windows
51import Network.Wai.Handler.Warp.Windows
@@ -218,7 +219,7 @@ acceptConnection set getConnMaker app counter ii0 = do
218 -- ensure that no async exception is throw between the call to
219 -- ensure that no async exception is throw between the call to
219 -- acceptNewConnection and the registering of connClose.
220 -- acceptNewConnection and the registering of connClose.
220 void $ mask_ acceptLoop
221 void $ mask_ acceptLoop
221− gracefulShutdown counter
222+ gracefulShutdown set counter
223 acceptLoop = do
224 acceptLoop = do
224 -- Allow async exceptions before receiving the next connection maker.
225 -- Allow async exceptions before receiving the next connection maker.
@@ -242,17 +243,14 @@ acceptConnection set getConnMaker app counter ii0 = do
242 ex <- try getConnMaker
243 ex <- try getConnMaker
243 case ex of
244 case ex of
244 Right x -> return $ Just x
245 Right x -> return $ Just x
245− Left e -> do
246+ Left e -> do
247+ let eConnAborted = getErrno eCONNABORTED
248+ getErrno (Errno cInt) = cInt
249+ if ioe_errno e == Just eConnAborted
250+ then acceptNewConnection
246− settingsOnException set Nothing $ toException e
252+ 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.
254− -- Assuming the listen socket is closed.
255− return Nothing
253+ return Nothing
257-- Fork a new worker thread for this connection maker, and ask for a
255-- Fork a new worker thread for this connection maker, and ask for a
258-- function to unmask (i.e., allow async exceptions to be thrown).
256-- function to unmask (i.e., allow async exceptions to be thrown).
@@ -498,5 +496,11 @@ setSocketCloseOnExec _ = return ()
498setSocketCloseOnExec socket = F.setFileCloseOnExec $ fromIntegral $ fdSocket socket
496setSocketCloseOnExec socket = F.setFileCloseOnExec $ fromIntegral $ fdSocket socket
501−gracefulShutdown :: Counter -> IO ()
499+gracefulShutdown :: Settings -> Counter -> IO ()
502−gracefulShutdown counter = waitForZero counter
500+gracefulShutdown set counter =
501+ case settingsGracefulShutdownTimeout set of
505+ void (timeout (seconds * microsPerSecond) (waitForZero counter))
506+ where microsPerSecond = 1000000