[Haskell-cafe] Printing of asynchronous exceptions to stderr

Simon Marlow marlowsd at gmail.com
Wed Nov 10 10:16:19 EST 2010


On 10/11/2010 14:32, Bas van Dijk wrote:
> On Wed, Nov 10, 2010 at 2:39 PM, Mitar<mmitar at gmail.com>  wrote:
>>> 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.)
>
> This is really interesting. Presumably what happens is that an
> exception is indeed thrown and then raised in the thread after the
> final action. Now if you synchronously throw an exception at the end
> it looks like it's raised before the asynchronous exception is raised.
>
> Hopefully one of the GHC devs (probably Simon Marlow) can confirm this
> behavior and shed some more light on it.

I think it's behaving as expected - there's a short window during which 
exceptions are unblocked and a second exception can be thrown.  The 
program has

   let run = doSomething `catches` [
                 Handler (\(_ :: MyTerminateException) -> return ()),
                 Handler (\(e :: SomeException) -> putStrLn $ 
"Exception: " ++ show e)
               ] `finally` (putMVar terminated ())
   nid <- forkIO run

The first MyTerminateException gets handled by the first exception 
handler.  This handler returns, and at that point exceptions are 
unblocked again, so the second MyTerminateException can be thrown.  The 
putMVar gets to run, and then the exception is re-thrown by finally, and 
caught and printed by the outer exception handler.

The right way to fix it is like this:

   let run = unblock doSomething `catches` [
                 Handler (\(_ :: MyTerminateException) -> return ()),
                 Handler (\(e :: SomeException) -> putStrLn $ 
"Exception: " ++ show e)
               ] `finally` (putMVar terminated ())
   nid <- block $ forkIO run

and the same will be true in GHC 7.0, except you'll need to use mask 
instead of block/unblock.

Cheers,
	Simon


More information about the Haskell-Cafe mailing list