asynchronous exceptions

Marcin 'Qrczak' Kowalczyk qrczak at knm.org.pl
Wed Apr 5 11:46:22 EDT 2006


"Simon Marlow" <simonmar at microsoft.com> writes:

> I'm not sure whether asynchronous exceptions should be in Haskell'.
> I don't feel entirely comfortable about the "interruptible operations"
> facet of the design,

I designed that differently for my language. There is a distinct
"synchronous mode" where asynchronous exceptions are handled by
certain operations only, similarly to POSIX deferred mode of thread
cancellation. This allows to use blocking operations without being
interrupted.

http://www.cs.ioc.ee/tfp-icfp-gpce05/tfp-proc/06num.pdf

Actually I support asynchronous signals, not just exceptions:
the reaction to a signal can be something other than throwing an
exception. For example Linux SIGWINCH should be handled by resizing
and repainting the screen at an appropriate moment, not by aborting
any computation in progress.

> The fact that throwTo can interrupt a takeMVar, but can't interrupt
> a foreign call, even a concurrent one, is a bit strange.

When entering "foreign mode" in C code embedded in Kogut (which
corresponds to concurrent foreign imports in Haskell but is less
convenient to use), it's possible to specify how that thread wishes
to be interrupted in case someone else sends it an asynchronous signal
during the foreign trip.

The only implemented application of this mechanism is sending a Unix
signal. This is enough to interrupt blocking syscalls like waitpid.
If waitpid fails and errno == EINTR, pending signals for this thread
are processed and waiting continues (unless some signal handler has
thrown an exception).

Implementing this without race conditions requires a sigsafe library
or something equivalent.


John Meacham <john at repetae.net> writes:

>  * do we require the thrower to 'block' until the signal is recieved?
>   (only relevant to pre-emptive implementations)

My language doesn't do it, and I'm not convinced that Haskell should
block. It's more efficient to make this non-blocking, and I think
usually this is what is needed.

>  * what happens if mutilple thrown exceptions "pile up" before the
>    catcher gets to them?

In my language each thread has a queue of pending asynchronous
signals, and they are processed in order.

Handling an asynchronous signal, or throwing an exception until it is
handled, blocks further signals automatically, so more signals are
processed only after the previous signal was handled.

An exception handler is not in a tail position wrt. the catching
construct, for two reasons: the state of asynchronous signals is
restored after handling the exception, and a stack trace shown when
the exception is propagated to the toplevel without being handled
includes code in unfinished exception handlers.

There is a separate exception handling syntax when the exception
should be considered already handled, for cases when the exception
handler should be in a tail context.

>  * what happns to exceptions that fall off the end of threads, or the
>    main thread? (should be answered anyway)

In my case a thread body ends with a value or with an exception,
and this can be examined when joining a thread, or by default the
exception is propagated in the joiner. This has a disadvantage
that errors in threads nobody waits for might be left undetected,
unless they use an explicit wrapper.

For the main thread there is a settable handler of exceptions
reaching the toplevel, which by default handles some exceptions
specially (Unix signals, and a request of program termination),
and others are printed along with a stack trace.

>  * promtness? how much work is the target allowed to do before it "sees"
>    the exception? pthreads allows an implementation to delay processing
>    an exception to a "cancellation point" do we want the same thing in
>    haskell?

Perhaps. My design includes that.


David Roundy <droundy at darcs.net> writes:

> It would also be nice to address signal behavior, and by default state that
> signals should be converted to asynchronous exceptions.

This is not enough for SIGWINCH, or for SIGHUP used to trigger
reloading configuration files.

OTOH purity of Haskell's functional subsystem has some nice
consequences for asynchronous exceptions which don't have to carry
over to asynchronous signals which don't necessarily abort the
computation. If the signal is guaranteed to abort some part of
IO code, then it makes sense to revert thunks under evaluation.
If the signal only causes to execute some handler, then reverting
them might be wasteful, as they will soon be needed again.

> The only downside I can see of this as default behavior would be
> that in cooperative systems the response to a sigTERM might be
> very slow.

Right, it's a pity, and I agree that benefits outweigh this problem.

In my implementation the thread which handles system signals
(settable, defaults to the main thread) needs to be chosen by the
scheduler in order to process the signal. It might take some time
if there is a lot of threads.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak at knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/


More information about the Haskell-prime mailing list