Signals + minimal proposal (was Re: asynchronous exceptions)

John Meacham john at repetae.net
Thu Apr 6 18:19:30 EDT 2006


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⑈


More information about the Haskell-prime mailing list