On 06/05/2011 16:56, dm-list-haskell-c...@scs.stanford.edu wrote:
At Fri, 6 May 2011 10:15:50 +0200,
Gregory Collins wrote:

Hi David,

Re: this comment from catchI:

It is not possible to catch asynchronous exceptions, such as
lazily evaluated divide-by-zero errors, the throw function, or
exceptions raised by other threads using throwTo if those
exceptions might arrive anywhere outside of a liftIO call.

It might be worth investigating providing a version which can catch
asynchronous exceptions if the underlying monad supports it (via
MonadCatchIO or something similar). One of the most interesting
advantages I can see for IterIO over the other iteratee
implementations is that you actually have some control over resource
usage -- not being able to catch asynchronous exceptions nullifies
much of that advantage. A clear use case for this is timeouts on
server threads, where you typically throw a TimeoutException exception
to the handling thread using "throwTo" if the timeout is exceeded.

Excellent point.  There's actually a chance that iterIO already
catches those kinds of exceptions, but I wasn't sure enough about how
the Haskell runtime works to make that claim.  I've noticed in
practice that asynchronous exceptions tend to come exactly when I
execute the IO>>= operation.  If that's true, then since each IO>>=
is wrapped in a try block, the exceptions will all be caught (well,
not divide by zero, but things like throwTo, which I think are more
important).

One way I was thinking of implementing this was wrapping the whole
execution in block, and then calling unblock (unless iterIO's own
hypothetical block function is called) for every invocation of liftIO.
Unfortunately, the block and unblock functions now seem to be
deprecated, and the replacement mask/unmask ones would not be as
amenable to this technique.

However, if there's some simpler way to guarantee that>>= is the
point where exceptions are thrown (and might be the case for GHC in
practice), then I basically only need to update the docs.  If someone
with more GHC understanding could explain how asynchronous exceptions
work, I'd love to hear it...

There's no guarantee of the form that you mention - asynchronous exceptions can occur anywhere. However, there might be a way to do what you want (disclaimer: I haven't looked at the implementation of iterIO).

Control.Exception will have a new operation in 7.2.1:

  allowInterrupt :: IO ()
  allowInterrupt = unsafeUnmask $ return ()

which allows an asynchronous exception to be thrown inside mask (until 7.2.1 you can define it yourself, unsafeUnmask comes from GHC.IO).

As I like saying, mask switches from fully asynchronous mode to polling mode, and allowInterrupt is the way you poll.

Cheers,
        Simon

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to