
On Fri, Nov 14, 2003 at 10:51:59PM +0100, Wolfgang Thaller wrote:
On Tue, Nov 11, 2003 at 09:39:05AM -0000, Simon Marlow wrote:
Hmm, there is clearly a choice between having a signal spawn a new thread or raise an asynchronous exception, and it's not at all clear which is best.
But, since we can implement either using the other one, it doesn't really matter too much which one is primitive.
How can the spawn-a-thread semantics be implemented using asynchronous exceptions? Doesn't the thread that the exception is thrown to unwind to the topmost handler?
You'd create a thread specifically for handling exceptions when you add your handler.
On 14.11.2003, at 16:21, David Roundy wrote:
In darcs, I really have no interest in dealing with signals, I just want to make sure my temporary files are cleaned up even if the user hits ^C. If the default signal handler uses exceptions, this will happen for free. Currently, my only choice for the former purpose is to use something like withSignal.
But the ^C signal itself is not, in general, sent to a specific thread; rather, it's sent to the whole process. So while it's reasonable to convert a SIGINT to an asynchronous exception thrown to a specific thread (as GHCi does), I don't see how that can be done generally. If you want bracket to clean up if the user hits ^C, you'd still have to hava a way of specifying which thread(s) get aborted using an exception on SIGINT. The default behaviour should lead to termination of the entire program; but in other situations (like GHCi for example), I'd probably want to catch the exception in one thread and have all other threads continue.
This doesn't seem like a problem. By default the exception goes to main (which aborts the whole program), and if you want to change which thread gets the exception that's fine.
I guess the problem is that as far as I can tell, there is no way to implement a "correct" bracket along with the existing POSIX signal implementation, since there's no way to find out what the current handler is, which means bracket can't install its own handler without messing up the current handler.
A way to find out the current handler could probably be added, but it'd still be impossible to implement a SIGINT-aware bracket because signal handlers are per-process, not per-thread.
Well, bracket doesn't work with concurrent programs even in the absense of signals (except in the main thread) so you don't lose anything there. If you write a concurrent program and want its threads to clean up, you always have to code that yourself, for example using a bracket in the main thread.
It still doesn't do what I'd really like, which is add default handlers for signals. I'd really like a
withSignalsAsExceptions :: IO a -> IO a
which would add an exception-throwing handler for *every* signal type (perhaps every asynchronous signal type...), and then run the default handler for any uncaught signals. Even better if main was automatically run in a withSignalsAsExceptions environment.
Wouldn't that render every signal that isn't intended to cause clean program shutdown next to useless? It seems perfect for SIGINT and SIGTERM, but I don't think that I'd want to handle SIGCONT or SIGCHLD as exceptions.
You're right. I was only thinking of exceptions that terminate, so you'd only want to throw exceptions for sigHUP, sigINT, sigALRM, sigTERM and possibly sigUSR1 and sigUSR2. I'm attaching the signal handling code I now actually use. It makes no provision for concurrency because I don't use any concurrency (although I do use pthreads). Actually, although I export catchSignal and throwSignal on matter of principle, I don't use them either. I just use main = withSignalsHandled $ do ... which does all I want done. -- David Roundy http://www.abridgegame.org