[Haskell-cafe] System.Exit

Stefan O'Rear stefanor at cox.net
Thu Jul 5 02:16:20 EDT 2007


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


More information about the Haskell-Cafe mailing list