
Hi All, Can anyone tell me what System.Exit.exitWith is actually supposed to do? As far as I can tell, it seems to be a synonym of (return ()). Okay, I'll stop being provocative and try and be helpful. So I have a web server, which like the one in The Literature(TM), essentially has a main loop: doit sok = do (reqSok,reqAddr) <- Network.Socket.accept sok forkIO (handleRequest reqSok reqAddr) doit sok This is all well and good, but how do you *stop* a server? Well, you have a request (blah blash auth blah blah) which tells it to shut down, /quit for example. I have a function to handle the quit request that looks something like: quitHandler sok addr .... = do tidyUpEverything .... sendOkResponse sok sClose sok System.Exit.exitWith ExitSuccess All nice and simple. All except one detail: it doesn't actually work. It prints exit: ExitSuccess but the "doit" loop keeps going. Of course, it goes totally spacko, because of the call to tidyUpEverything, but it doesn't exit. So, if I set an IORef/TVar inside quitHandler which I inspect either just before or just after the call to Network.Socket.accept, I could exit the loop, but that only helps once the next request comes in. I contemplated a solution involving Control.Exception.throwTo, but I actually read the doco (!) which states the following: <quote> If the target thread is currently making a foreign call, then the exception will not be raised (and hence throwTo will not return) until the call has completed. This is the case regardless of whether the call is inside a block or not. </quote> So no joy there. Ideas anyone? And is exitWith broken, or is it the doco that's broken? cheers, T. -- Dr Thomas Conway drtomc@gmail.com Silence is the perfectest herald of joy: I were but little happy, if I could say how much.

On Jul 5, 2007, at 0:04 , Thomas Conway wrote:
quitHandler sok addr .... = do tidyUpEverything .... sendOkResponse sok sClose sok System.Exit.exitWith ExitSuccess
All nice and simple. All except one detail: it doesn't actually work.
It prints
exit: ExitSuccess
but the "doit" loop keeps going. Of course, it goes totally spacko, because of the call to tidyUpEverything, but it doesn't exit.
So, if I set an IORef/TVar inside quitHandler which I inspect either just before or just after the call to Network.Socket.accept, I could exit the loop, but that only helps once the next request comes in.
I contemplated a solution involving Control.Exception.throwTo, but I actually read the doco (!) which states the following:
<quote> If the target thread is currently making a foreign call, then the
If you're making foreign calls and using forkIO, then there will be at least two OS threads running. In this case, the process generally won't exit until all the OS threads do. Since this is the OS's doing, as far as the Haskell runtime is concerned System.Exit has done the right thing, but the other OS thread(s) won't have been notified to shut down so they'll just keep going until told otherwise. I think the proper action here is that your quitHandler sets an MVar/ TVar to indicate that things should start shutting down, then either shut down its thread or, if it's in the main thread, wait for the other threads to terminate and then invoke System.Exit. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On Thu, Jul 05, 2007 at 02:04:32PM +1000, Thomas Conway wrote:
Hi All,
Can anyone tell me what System.Exit.exitWith is actually supposed to do? As far as I can tell, it seems to be a synonym of (return ()).
Okay, I'll stop being provocative and try and be helpful.
So I have a web server, which like the one in The Literature(TM), essentially has a main loop:
doit sok = do (reqSok,reqAddr) <- Network.Socket.accept sok forkIO (handleRequest reqSok reqAddr) doit sok
This is all well and good, but how do you *stop* a server? Well, you have a request (blah blash auth blah blah) which tells it to shut down, /quit for example.
I have a function to handle the quit request that looks something like:
quitHandler sok addr .... = do tidyUpEverything .... sendOkResponse sok sClose sok System.Exit.exitWith ExitSuccess
All nice and simple. All except one detail: it doesn't actually work.
It prints
exit: ExitSuccess
but the "doit" loop keeps going. Of course, it goes totally spacko, because of the call to tidyUpEverything, but it doesn't exit.
So, if I set an IORef/TVar inside quitHandler which I inspect either just before or just after the call to Network.Socket.accept, I could exit the loop, but that only helps once the next request comes in.
I contemplated a solution involving Control.Exception.throwTo, but I actually read the doco (!) which states the following:
<quote> If the target thread is currently making a foreign call, then the exception will not be raised (and hence throwTo will not return) until the call has completed. This is the case regardless of whether the call is inside a block or not. </quote>
So no joy there.
Ideas anyone?
And is exitWith broken, or is it the doco that's broken?
The documentation says: | Computation exitWith code throws ExitException code. Normally this | terminates the program, returning code to the program's caller. Before | the program terminates, any open or semi-closed handles are first | closed. | | As an ExitException is not an IOError, exitWith bypasses the error | handling in the IO monad and cannot be intercepted by catch from the | Prelude. However it is an Exception, and can be caught using the | functions of Control.Exception. This means that cleanup computations | added with bracket (from Control.Exception) are also executed properly | on exitWith. Probably some part of your code is catching all exceptions, printing them, and then ignoring them; thus negating the exit request. If you want to ignore all exceptions, you can still use exitImmediately from the unix package, but all the usual caveats (unflushed file buffers, no synchronization, no profile output) apply. Stefan

On Wed, Jul 04, 2007 at 11:16:20PM -0700, Stefan O'Rear wrote:
The documentation says: | Computation exitWith code throws ExitException code. Normally this | terminates the program, returning code to the program's caller. Before | the program terminates, any open or semi-closed handles are first | closed. | | As an ExitException is not an IOError, exitWith bypasses the error | handling in the IO monad and cannot be intercepted by catch from the | Prelude. However it is an Exception, and can be caught using the | functions of Control.Exception. This means that cleanup computations | added with bracket (from Control.Exception) are also executed properly | on exitWith.
Probably some part of your code is catching all exceptions, printing them, and then ignoring them; thus negating the exit request.
I think the problem here is that uncaught exception are not propagated from child threads to the main thread (I'm not claiming that they should be) and ExitException only ends the program when caught in the main thread, as it seems. Try this: import Control.Concurrent import System.Exit main = do forkIO $ exitWith ExitSuccess threadDelay 10000000 Best regards Tomek

FWIW, I implemented the STM based solution, and it works a treat. It's less of a hack than the version where I got the child thread to send a SIGINT. ;-) T. -- Dr Thomas Conway drtomc@gmail.com Silence is the perfectest herald of joy: I were but little happy, if I could say how much.
participants (4)
-
Brandon S. Allbery KF8NH
-
Stefan O'Rear
-
Thomas Conway
-
Tomasz Zielonka