[Haskell-cafe] Printing of asynchronous exceptions to stderr

Simon Marlow marlowsd at gmail.com
Wed Nov 10 10:48:32 EST 2010


On 10/11/2010 13:39, Mitar wrote:

> I know that (I read one post from you some time ago). It is in TODO
> commend before this code. I am waiting for GHC 7.0 for this because I
> do not like current block/unblock approach.
>
> Because blocked parts can still be interrupted, good example of that
> is takeMVar. The other is (almost?) any IO. So if code would be:
>
> block $ forkIO $ do
>    putStrLn "Forked"
>    (unblock doSomething) `finally` (putMVar terminated ())
>
> There is a chance that putStrLn gets interrupted even with block.

The new async exceptions API isn't going to significantly change things 
in this area.  You still have interruptible operations that can receive 
async exceptions, and you don't know when you call an IO function in a 
library whether it uses interruptible operations or not.

The new API means that things like withMVar that previously would 
unblock async exceptions even when called inside block no longer do 
that.  But that doesn't affect whether a library function that you have 
no control over can raise async exceptions or not.

You can use maskUninterruptible in GHC 7, but that is not generally 
recommended, because of the danger that you make your program 
unresponsive to ^C indefinitely.  If you can be sure that the the code 
will only be blocked for a short time, then maskUninterruptible might be 
justified, but I think that case is rare.  e.g. putStrLn could certainly 
block indefintely.

So let's be clear about this.  Inside mask (previously block), the 
following things can raise asynchronous exceptions:

  - interruptible operations (MVar operations, throwTo, atomically)

Since we can't be certain that an IO operation from a library does not 
invoke any interruptible operations, we have to assume that all IO 
functions from libraries can raise async exceptions.

Well, maybe that's a bit conservative.  If it were really true then 
there wouldn't be much point in mask at all, since the only things you 
can meaningfully do inside IO involve calling library functions.  So we 
should say there are a few things that you can do that guarantee not to 
call any interruptible operations:

  - IORef operations
  - STM transactions that do not use retry
  - everything from the Foreign.* modules

and probably some other things.  Maybe we should put this list in the 
documentation.

Cheers,
	Simon



  So
> for me it is better to have a big TODO warning before the code than to
> use block and believe that this is now fixed. And when I will add some
> code one year later I will have problems. Of course I could add a
> comment warning not to add any IO before finally. But I want to have a
> reason to switch to GHC 7.0. ;-)
>
> I am using such big hack for this:
>
> -- Big hack to prevent interruption: it simply retries interrupted computation
> uninterruptible :: IO a ->  IO a
> uninterruptible a = block $ a `catch` (\(_ :: SomeException) ->
> uninterruptible a)
>
> So I can call "uninterruptible $ takeMVar terminated" and be really
> sure that I have waited for thread to terminate. Not that thread in
> its last breaths send me some exception which interrupted me waiting
> for it and thus not allowing it to terminate properly. Of course if
> you now that you do not want that your waiting is interrupted in any
> way. Maybe there could be an UserInterrupt exception to this
> uninterruptible way of handling exceptions. ;-)
>
>> I've made this same error and have seen others make it too. For this
>> reason I created the threads[1] package to deal with it once and for
>> all.
>
> I know. I checked it. But was put off by mention of "unsafe".
>
>> Strange. It would help if you could show more of of your code.
>
> I am attaching a sample program which shows this. I am using 6.12.3 on
> both Linux and Mac OS X. And I run this program with runhaskell
> Test.hs. Without "throwIO ThreadKilled" it outputs:
>
> Test.hs: MyTerminateException
> MVar was successfully taken
>
> With "throwIO ThreadKilled" is as expected, just:
>
> MVar was successfully taken
>
> So MVar is filled. What means that thread gets exception after that.
> But there is nothing after that. ;-) (At least nothing visible.)
>
>
> Mitar
>
>
>
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users



More information about the Haskell-Cafe mailing list