
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 http://www.darcs.net