
On Wed, Apr 05, 2006 at 03:41:55PM +0100, Simon Marlow wrote:
I have been giving signals some thought, and resarching what other languages do, and have a semi-proposal-maybe.
We should be careful here: the Haskell standard has so far remained platform-independent, and I think it would be nice to keep it that way.
Signals arn't as bad as some things, as a platform that doesn't support signals would just be visibly the same as one where the signals never happen to be generated. in any case, a signal-safe haskell program will be portable. assuming we don't make the ability to _send_ a signal part of the standard.
I'm not proposing that we ignore signals, just that we should clearly delimit the platform-specific bits, perhaps by putting signal support into an addendum.
yeah, I was thinking a separate environment addendum should be in the report, which takes behavior that is undefined in the language standard, and defines it for various platforms. it wouldn't extend the functionality or scope of the standard, just define what couldn't be defined in the standard. like the standard might say "the set of signals is undefined" while the UNIX addendum will say "the set of signals will include at least SIGINT,SIGHUP,etc..."
GHC has no support for these right now. They're pretty tricky to handle, because the OS thread that caused the signal to be raised is stopped at some arbitrary instruction, and it would require some serious acrobatics to munge that OS thread into a state where it is possible to raise the (Haskell) exception. I do vaguely recall that people have achieved this in the past, in order to use page faults for write barriers, that sort of thing.
how does ghc handle things like divide by zero then?
SIGPIPE is possibly easier than the others. SIGFPE you can usually turn off in favour of "exceptional values" instead.
yeah, I was thinking we should make these the default in the unix addendum.
signal an asynchronous exceptional event - the user should be able to choose the threads on which they wish to catch these, those that need to clean up after themselves.
inform the app of an event it might want to take note of - these should run on their own thread, concurrently to all other threads
GHC directly support the latter version, and you can implement the former with a little extra code and a global variable. I think it would be nice to do as you suggest and provide a way to have the async signals turn directly into exceptions.
One problem, though, is that because we can't interrupt a foreign call with an async exception, ^C can be rather unresponsive. Perhaps I should look into this and see whether it would be possible in GHC for a concurrent foreign call to be interruptible; it would involve terminating the foreign call somehow (pthread_cancel?) before raising the exception. We can't do this in a bound thread, however.
You should be able to handle the SIGINT imediatly no matter whether foregin code is running if your handler is in its own thread right? just have the C signal handler write a byte to a pipe, your haskell signal handler thread is in a repeatM $ do readExactlyOneByte signalHandler loop. so will run immediatly no matter what thread the async signal was delivered to. the same solution will work in cooperative implementations, but are subject to normal scheduling latency issues. = minimal proposal = I think a good minimal solution will be the following, it neatly avoids turning signals into exceptions, which may be problematic, but provides for the common cases of signal usages while being compatible with both cooperative and SMP systems. == catching signals == implementations provide a way of catching signals such that the handler runs as if in its own thread. something like the following data SigInfo = ... data HandlerType = SigOneShot | SigReset | SigIdempotent data SigAction = SigAction { signalType :: HandlerType, signalAction :: SigInfo -> IO () } | SigDefault | SigIgnore | SigExit (SigInfo -> ExitStatus) installHandler :: Signal -> SigAction -> IO SigAction installHandler = ... the action runs in its own thread. SigExit is special in that it is equivalent to a 'signalAction' that just calls exit, but since you know the program is going to exit, the implementation can jump to the exit handler immediatly aborting the current computation in whatever state it is in since it knows it will never return to it. SigIdempotent is the same as SigReset except multiple signals are condensed into one with the SigInfo being chosen non-deterministically from all those available. == on exit == implementations also provide an onExit functionality, for registering handlers that can be run when the program exits, as this is the most common use of signals as exceptions, to clean up after oneself. -- | temporarily register an exit handler for the duration of the action argument withExitHandler :: IO () -> IO a -> IO a withExitHandler = .... -- | register a handler to be run on exiting the program onExit :: IO () -> IO () onExit = .... -- | block exiting during this call for critical sections. blockExit :: IO a -> IO a blockExit = ... although thees are less powerful than exceptions in that you can only catch a single event, "exit" they are more powerful in the sense that the exception handlers are global, so when you register an exit handler it happens no matter what thread is in scope. in addition, an exit_ routine should be added that bypasses the exit handlers, quiting the program immediatly. John -- John Meacham - ⑆repetae.net⑆john⑈