Problems with Network/MVar

Hello cafe, I’m trying to run a server to synchronize a bunch of machines, and one of the threads keeps crashing every ~50 hours. One of the threads is an HTTP server and stays alive forever, so it’s not a Unix signal problem. I don’t have much information on its stdout/stderr, and the bug is not very reproducible, since it can happen even though very few of its maximum ~200 clients are connected. Is there a reason why the following can stop after some time? server::Config -> MVar State -> IO () server config state=withSocketsDo $ do installHandler sigPIPE Ignore Nothing threads<-Sem.new $ maxThreads config forever $ do E.catch (bracket (listenOn $ port config)) sClose $ \sock->forever $ do (s,a,_)<-accept sock wait threads forkIO $ (reply state s a)`finally`(signal threads)`E.catch`(\e->let _=e::IOException in return ()) (\e->let _=e::IOException in return ()) threadDelay 100000 This was compiled with GHC 7.6.3, -threaded and run on Debian Jessie (I have not tested other settings), and Config and State are both record types. Thanks, Pierre

On Tue, Apr 1, 2014 at 11:21 AM, Pierre-Étienne Meunier < pierreetienne.meunier@gmail.com> wrote:
Hello cafe,
I’m trying to run a server to synchronize a bunch of machines, and one of the threads keeps crashing every ~50 hours.
You seem to be throwing away the exception messages so it will be difficult to diagnose why. server::Config -> MVar State -> IO ()
server config state=withSocketsDo $ do installHandler sigPIPE Ignore Nothing threads<-Sem.new $ maxThreads config forever $ do E.catch (bracket (listenOn $ port config)) sClose $ \sock->forever $ do (s,a,_)<-accept sock
There is a race condition here, you can get an asynchronous exception any time after accepting the socket that would cause it to leak open. I'm guessing you might running out of file descriptors. This whole section should be run under "mask" and you should only unmask async exceptions when you know you've installed a signal handler to clean up afterwards.
wait threads forkIO $ (reply state s a)`finally`(signal threads)`E.catch`(\e->let _=e::IOException in return ())
Try "forkIOWithUnmask", same advice applies in the child thread.
G
--
Gregory Collins

Em 01/04/2014, à(s) 11:29, Gregory Collins
On Tue, Apr 1, 2014 at 11:21 AM, Pierre-Étienne Meunier
wrote: Hello cafe,
I’m trying to run a server to synchronize a bunch of machines, and one of the threads keeps crashing every ~50 hours.
You seem to be throwing away the exception messages so it will be difficult to diagnose why.
You’re right, that was really stupid. It is my first time dealing with (exceptions+threads+network) in Haskell.
server::Config -> MVar State -> IO () server config state=withSocketsDo $ do installHandler sigPIPE Ignore Nothing threads<-Sem.new $ maxThreads config forever $ do E.catch (bracket (listenOn $ port config)) sClose $ \sock->forever $ do (s,a,_)<-accept sock
There is a race condition here, you can get an asynchronous exception any time after accepting the socket that would cause it to leak open. I'm guessing you might running out of file descriptors. This whole section should be run under "mask" and you should only unmask async exceptions when you know you've installed a signal handler to clean up afterwards.
Is this the same as using “bracket accept hClose $ blabla” (modulo correct types)?
wait threads forkIO $ (reply state s a)`finally`(signal threads)`E.catch`(\e->let _=e::IOException in return ())
Try "forkIOWithUnmask", same advice applies in the child thread.
Thanks. Let’s see how it goes in two days. Pierre

On Tue, Apr 1, 2014 at 1:35 PM, Pierre-Étienne Meunier < pierreetienne.meunier@gmail.com> wrote:
Is this the same as using “bracket accept hClose $ blabla” (modulo correct types)?
Sort of (and you could turn this pattern into a similar combinator), except
here you want to accept the socket and hand it off to a child thread. In
order to make that pattern safe you have to use mask:
foo = mask $ \unmask -> do
(s, a, _) <- unmask $ accept sock
-- here async exceptions are blocked which gives you time to
install a signal
-- handler, you only unmask exceptions once the handler is installed
forkIOWithUnmask $ \restore -> ((restore $ reply state s a) `catch`
handler) `finally` (cleanup s a)
--
Gregory Collins
participants (2)
-
Gregory Collins
-
Pierre-Étienne Meunier