@@ -64,7 +64,7 @@ module Network.Wai.Handler.Warp
67−import Prelude hiding (lines)
67+import Prelude hiding (lines, catch)
68import Network.Wai
68import Network.Wai
70import Data.ByteString (ByteString)
70import Data.ByteString (ByteString)
@@ -76,9 +76,9 @@ import Network (sClose, Socket)
76import Network.Socket (accept, SockAddr)
76import Network.Socket (accept, SockAddr)
77import qualified Network.Socket.ByteString as Sock
77import qualified Network.Socket.ByteString as Sock
78import Control.Exception
78import Control.Exception
79− ( mask, handle, onException, bracket
79+ ( mask, catch, handle, onException, bracket
80− , Exception, SomeException
80+ , Exception, SomeException, IOException, AsyncException (ThreadKilled)
81− , fromException, AsyncException (ThreadKilled)
81+ , fromException, toException
83#if __GLASGOW_HASKELL__ >= 702
83#if __GLASGOW_HASKELL__ >= 702
84 , allowInterrupt
84 , allowInterrupt
@@ -89,7 +89,7 @@ import Control.Exception
92−import Control.Concurrent (forkIO)
92+import Control.Concurrent (forkIO, threadDelay)
93import Data.Maybe (fromMaybe, isJust)
93import Data.Maybe (fromMaybe, isJust)
94import Data.Char (toLower, isHexDigit)
94import Data.Char (toLower, isHexDigit)
95import Data.Word (Word)
95import Data.Word (Word)
@@ -127,7 +127,6 @@ import qualified Data.IORef as I
127import Data.Conduit.Network (bindPort, HostPreference (HostIPv4))
127import Data.Conduit.Network (bindPort, HostPreference (HostIPv4))
129#if WINDOWS
129#if WINDOWS
130−import Control.Concurrent (threadDelay)
131import qualified Control.Concurrent.MVar as MV
130import qualified Control.Concurrent.MVar as MV
132import Network.Socket (withSocketsDo)
131import Network.Socket (withSocketsDo)
@@ -221,21 +220,29 @@ runSettingsSocket set socket app =
222runSettingsConnection :: Settings -> IO (Connection, SockAddr) -> Application -> IO ()
221runSettingsConnection :: Settings -> IO (Connection, SockAddr) -> Application -> IO ()
223runSettingsConnection set getConn app = do
222runSettingsConnection set getConn app = do
224− let onE = settingsOnException set
225− port = settingsPort set
226− onOpen = settingsOnOpen set
227− onClose = settingsOnClose set
228 tm <- maybe (T.initialize $ settingsTimeout set * 1000000) return
223 tm <- maybe (T.initialize $ settingsTimeout set * 1000000) return
229 $ settingsManager set
224 $ settingsManager set
230 mask $ \restore -> forever $ do
225 mask $ \restore -> forever $ do
231 allowInterrupt
226 allowInterrupt
232− (conn, addr) <- getConn
227+ (conn, addr) <- getConnLoop
233 void $ forkIO $ do
228 void $ forkIO $ do
234 th <- T.registerKillThread tm
229 th <- T.registerKillThread tm
235 handle onE $ (do onOpen
230 handle onE $ (do onOpen
236 restore $ serveConnection set th port app conn addr
231 restore $ serveConnection set th port app conn addr
237 connClose conn >> T.cancel th >> onClose
232 connClose conn >> T.cancel th >> onClose
238 ) `onException` (T.cancel th >> connClose conn >> onClose)
233 ) `onException` (T.cancel th >> connClose conn >> onClose)
235+ -- FIXME: only IOEception is caught. What about other exceptions?
236+ getConnLoop = getConn `catch` \(e :: IOException) -> do
238+ -- "resource exhausted (Too many open files)" may happen by accept().
239+ -- Wait a second hoping that resource will be available.
242+ onE = settingsOnException set
243+ port = settingsPort set
244+ onOpen = settingsOnOpen set
245+ onClose = settingsOnClose set
240-- | Contains a @Source@ and a byte count that is still to be read in.
247-- | Contains a @Source@ and a byte count that is still to be read in.
241newtype IsolatedBSSource = IsolatedBSSource (I.IORef (Int, ResumableSource (ResourceT IO) ByteString))
248newtype IsolatedBSSource = IsolatedBSSource (I.IORef (Int, ResumableSource (ResourceT IO) ByteString))