asynchronous exceptions (was: RE: Concurrency)

David Roundy droundy at
Wed Apr 5 07:47:08 EDT 2006

On Tue, Apr 04, 2006 at 01:33:39PM +0100, Simon Marlow wrote:
> 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, and I'm hoping that STM can clean things up: after
> all, STM already gives you a much nicer way to program in an
> exception-safe way, as long as you aren't doing any real I/O.

For me, asynchronous exceptions are the primary reason to use concurrent
Haskell.  They're the only way I'm aware of to write a program that handles
signals in Haskell, and it's be a real shame to leave Haskell' programs
unable to handle signals--it means that any real-world programs that deal
with locking or the like will need to use non-standard extensions.  Unless
you can come up with some other way to deal with signals.  Having no chance
to clean up when control-C is hit isn't an acceptable alternative, and
neither is simply ignoring control-C and forcing users to run kill (and
then once again get no chance to clean up!).

Another option would be to hard-code signals into some sort of ordinary
exceptions, but that's not very good, since you'd then still want to split
exceptions into two camps, so that you could run a catch that only catches
signals generated *by* the IO action that you're running (i.e. you often
want to "remove a file, and ignore any sort of failure", but don't want to
accidentally ignore a sigTERM that arrives during this process).  I suppose
you could do this with the complicated catchJust, but that's a pain.  It's
nice having a small (and documented) set of exceptions that most IO
operations can throw.

> The fact that throwTo can interrupt a takeMVar, but can't interrupt a
> foreign call, even a concurrent one, is a bit strange.  We have this odd
> situation in GHC right now where throwTo can interrupt threadDelay on
> Unix, but not on Windows because threadDelay maps directly to a foreign
> call to Sleep() on Windows.  To fix this I have to implement the I/O
> manager thread on Windows (I should do this anyway, though).
> The only guarantee you can give is "the exception isn't delayed
> indefinitely, unless the target thread remains inside a block".  Just
> like the fairness property for MVars.

I think this is fine.  There's no need for strong guarantees that
asynchronous exceptions are delivered soon or interrrupt any particular
external function calls, or even interrupt particular standard library
functions.  At least to me, that's what makes them asynchronous.  In other
words, I wouldn't mind cooperative asynchronous function calls.  Which is
to say, that I don't see any reason the standard IO library shouldn't be
allowed (by the standard) to use block in all its calls.

This does limit the power of their application to signal-handling, but if
you really want signal-catching in ffi functions, those functions could
install their own signal-catchers.  My main concern is that as far as I can
see, without asynchronous exceptions there's no way to implement this sort
of functionality in pure Haskell.

Actually, I suppose you could do this with a (cooperative) implementation
of asynchronous exceptions using just MVars and concurrency by rewriting
all the IO calls you use to first check whether an asynchronous exception
has been thrown, but rewriting all the std library functions seems like a
rather crude way of doing this.  On the other hand, I suppose that this
could also provide a reference implementation of asynchronous exceptions
for any Haskell' that supports concurrency...
David Roundy

More information about the Haskell-prime mailing list