Treating POSIX signals as exceptions?

I was wondering why System.Posix.Signals is as it is, and whether it could be rewritten to use exceptions, which seems like the obvious way to handle signals. Of course, that requires asynchronous exceptions, but that doesn't seem like a severe problem. What I currently do is to use the following function withSig :: Signal -> IO a -> IO a -> IO a withSig s handler job = do id <- myThreadId installHandler s (Catch $ throwDynTo id s) Nothing job `catchDyn` catcher where catcher s' | s' == s = handler catcher s' = throwDyn s' which just catches a given signal and throws an exception, and then catches that exception with a given default handler. This has the nice effect that my 'job' can't be rudely interrupted by the user hitting ^C at just the wrong time (since I use this to catch sigINT). Thus, this makes bracket work in the presence of signals, allows me to use block to avoid being interrupted by a ^C when this could cause data corruption, etc. (Yes, I know that the above isn't very clean, since any other process that uses {catch,throw}Dyn on a CInt will mess things up, but creating a new Typeable instance seemed like too much trouble.) Is there any reason all of System.Posix.Signals couldn't be done in this manner? Have the RTS always add a handler for each signal, which just throws an exception. Off the top of my head, all we'd need is one function acceptSignals :: IO () -- tells RTS to send signal exceptions to this -- thread. We'd also need some sort of SignalException type (and of course, to define all the signals), and the rest would be done using the existing Control.Exception code. And, of course, default signal handlers would need to be converted to default exception handlers. Is there a problem with this idea? -- David Roundy http://www.abridgegame.org/darcs

W liĆcie z pon, 10-11-2003, godz. 16:41, David Roundy pisze:
I was wondering why System.Posix.Signals is as it is, and whether it could be rewritten to use exceptions, which seems like the obvious way to handle signals.
I don't understand. How to handle a signal using exceptions such that the signal doesn't abort the execution up to the nearest established handler? -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/

On Tue, Nov 11, 2003 at 04:49:29PM +0100, Marcin 'Qrczak' Kowalczyk wrote:
On, 10-11-2003, at 16:41, David Roundy wrote:
I was wondering why System.Posix.Signals is as it is, and whether it could be rewritten to use exceptions, which seems like the obvious way to handle signals.
I don't understand. How to handle a signal using exceptions such that the signal doesn't abort the execution up to the nearest established handler?
That's precisely what it would do (which seems better than simply aborting execution...). If you don't want that behavior, you would forkIO a thread to receive the exceptions. -- David Roundy http://www.abridgegame.org

On Mon, Nov 10, 2003 at 10:41:32AM -0500, David Roundy wrote:
I was wondering why System.Posix.Signals is as it is, and whether it could be rewritten to use exceptions, which seems like the obvious way to handle signals. Of course, that requires asynchronous exceptions, but that doesn't seem like a severe problem.
What I currently do is to use the following function
withSig :: Signal -> IO a -> IO a -> IO a withSig s handler job = do id <- myThreadId installHandler s (Catch $ throwDynTo id s) Nothing job `catchDyn` catcher where catcher s' | s' == s = handler catcher s' = throwDyn s'
which just catches a given signal and throws an exception, and then catches that exception with a given default handler. This has the nice effect that my 'job' can't be rudely interrupted by the user hitting ^C at just the wrong time (since I use this to catch sigINT). Thus, this makes bracket work in the presence of signals, allows me to use block to avoid being interrupted by a ^C when this could cause data corruption, etc.
There is a strong difference between asynchronous signals (like SIGIO, SIGINT, etc..) and synchronous ones (SIGFPE, SIGSEG). I think only the second type should be treated as exceptions, since they are tied to a specific thread of execution. tying asynchronous signals to exceptions just because they are posted to the program in the same way seems wrong. especially when we have concurrency. registering a callback, or even having a 'wait' like thing to blockingly wait for the next asynchronous signal would be ideal. note that the POSIX real-time (and threading) specifications make the distinction between the two signal types and handle them differently so there is precidence.
(Yes, I know that the above isn't very clean, since any other process that uses {catch,throw}Dyn on a CInt will mess things up, but creating a new Typeable instance seemed like too much trouble.)
Is there any reason all of System.Posix.Signals couldn't be done in this manner? Have the RTS always add a handler for each signal, which just throws an exception. Off the top of my head, all we'd need is one function
well, we would want to ignore many signals for one thing. once an exception is thrown, it is hard to 'un-throw'. (although, if someone invented a way to do it, that would be groovy..)
acceptSignals :: IO () -- tells RTS to send signal exceptions to this -- thread.
We'd also need some sort of SignalException type (and of course, to define all the signals), and the rest would be done using the existing Control.Exception code. And, of course, default signal handlers would need to be converted to default exception handlers.
we need some data type which contains the information in the 'siginfo_t' structure. then we can include this as a standard Exception type for use with synchronous signals. -- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------
participants (3)
-
David Roundy
-
John Meacham
-
Marcin 'Qrczak' Kowalczyk