mask, catch, myThreadId, throwTo

Hey! I have some code that is not behaving the way I thought it should. The gist of it is sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through. However, that's not what I am seeing. Running with -threaded and at least -N2 I can reliably get sleeper to be killed. Please see the complete code at: https://gist.github.com/meteficha/5390079 The expected result is 100 Pongs and 0 Pings. Running with -N1 that's what I get. Running with -N2 I get a few Pongs and then 1 Ping. Running with -N3 or more usually gives me just 1 Ping and not a single Pong. I'm testing with GHC 7.4.1. I've tried to download 7.7 but---either because of haskell.org or my ISP---I'm not being able to download it. (Note that this problem is not academic as I've been bitten by it on my production code.) Thanks! =D -- Felipe.

Felipe Almeida Lessa wrote:
I have some code that is not behaving the way I thought it should.
The gist of it is
sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack
throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping
Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through.
(c) is wrong, throwTo may block, and blocking operations are interruptible. http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception... explains this in some more detail. The simplest way that throwTo can actually block in your program, as far as I can see, and one that will only affect the threaded RTS, is if the sleeper thread and whichever thread is running the other throwBack are executing on different capabilities; this will always cause throwTo to block. (You could try looking at a ghc event log to find out more.) I last ran into trouble like that with System.Timeout.timeout; for that function I finally convinced myself that uninterruptibleMask is the only way to avoid such problems; then throwTo will not be interrupted by exceptions even when it blocks. Maybe this is the solution for your problem, too. Hope that helps, Bertram

Thanks a lot, you're correct! The trouble is, I was misguided by the
"Interruptible operations" note [1] which states that
The following operations are guaranteed not to be interruptible:
... * everything from Control.Exception ...
Well, it seems that not everything from Control.Exception fits the bill.
Thanks, =)
[1] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
On Mon, Apr 15, 2013 at 5:25 PM, Bertram Felgenhauer
Felipe Almeida Lessa wrote:
I have some code that is not behaving the way I thought it should.
The gist of it is
sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack
throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping
Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through.
(c) is wrong, throwTo may block, and blocking operations are interruptible.
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
explains this in some more detail.
The simplest way that throwTo can actually block in your program, as far as I can see, and one that will only affect the threaded RTS, is if the sleeper thread and whichever thread is running the other throwBack are executing on different capabilities; this will always cause throwTo to block. (You could try looking at a ghc event log to find out more.)
I last ran into trouble like that with System.Timeout.timeout; for that function I finally convinced myself that uninterruptibleMask is the only way to avoid such problems; then throwTo will not be interrupted by exceptions even when it blocks. Maybe this is the solution for your problem, too.
Hope that helps,
Bertram
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
-- Felipe.

Sounds like those docs need to be fixed, in that case. Edward Excerpts from Felipe Almeida Lessa's message of Mon Apr 15 13:34:50 -0700 2013:
Thanks a lot, you're correct! The trouble is, I was misguided by the "Interruptible operations" note [1] which states that
The following operations are guaranteed not to be interruptible: ... * everything from Control.Exception ...
Well, it seems that not everything from Control.Exception fits the bill.
Thanks, =)
[1] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
On Mon, Apr 15, 2013 at 5:25 PM, Bertram Felgenhauer
wrote: Felipe Almeida Lessa wrote:
I have some code that is not behaving the way I thought it should.
The gist of it is
sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack
throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping
Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through.
(c) is wrong, throwTo may block, and blocking operations are interruptible.
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
explains this in some more detail.
The simplest way that throwTo can actually block in your program, as far as I can see, and one that will only affect the threaded RTS, is if the sleeper thread and whichever thread is running the other throwBack are executing on different capabilities; this will always cause throwTo to block. (You could try looking at a ghc event log to find out more.)
I last ran into trouble like that with System.Timeout.timeout; for that function I finally convinced myself that uninterruptibleMask is the only way to avoid such problems; then throwTo will not be interrupted by exceptions even when it blocks. Maybe this is the solution for your problem, too.
Hope that helps,
Bertram
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

OK, I've updated the docus. Excerpts from Felipe Almeida Lessa's message of Mon Apr 15 13:34:50 -0700 2013:
Thanks a lot, you're correct! The trouble is, I was misguided by the "Interruptible operations" note [1] which states that
The following operations are guaranteed not to be interruptible: ... * everything from Control.Exception ...
Well, it seems that not everything from Control.Exception fits the bill.
Thanks, =)
[1] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
On Mon, Apr 15, 2013 at 5:25 PM, Bertram Felgenhauer
wrote: Felipe Almeida Lessa wrote:
I have some code that is not behaving the way I thought it should.
The gist of it is
sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack
throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping
Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through.
(c) is wrong, throwTo may block, and blocking operations are interruptible.
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
explains this in some more detail.
The simplest way that throwTo can actually block in your program, as far as I can see, and one that will only affect the threaded RTS, is if the sleeper thread and whichever thread is running the other throwBack are executing on different capabilities; this will always cause throwTo to block. (You could try looking at a ghc event log to find out more.)
I last ran into trouble like that with System.Timeout.timeout; for that function I finally convinced myself that uninterruptibleMask is the only way to avoid such problems; then throwTo will not be interrupted by exceptions even when it blocks. Maybe this is the solution for your problem, too.
Hope that helps,
Bertram
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Nice, thanks, Edward =).
On Tue, Apr 16, 2013 at 6:20 PM, Edward Z. Yang
OK, I've updated the docus.
Excerpts from Felipe Almeida Lessa's message of Mon Apr 15 13:34:50 -0700 2013:
Thanks a lot, you're correct! The trouble is, I was misguided by the "Interruptible operations" note [1] which states that
The following operations are guaranteed not to be interruptible: ... * everything from Control.Exception ...
Well, it seems that not everything from Control.Exception fits the bill.
Thanks, =)
[1] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
On Mon, Apr 15, 2013 at 5:25 PM, Bertram Felgenhauer
wrote: Felipe Almeida Lessa wrote:
I have some code that is not behaving the way I thought it should.
The gist of it is
sleeper = mask_ $ forkIOWithUnmask $ \restore -> forever $ restore sleep `catch` throwBack
throwBack (Ping tid) = myThreadId >>= throwTo tid . Pong throwBack (Pong tid) = myThreadId >>= throwTo tid . Ping
Since (a) throwBack is executed on a masked state, (b) myThreadId is uninterruptible, and (c) throwTo is uninterruptible, my understanding is that the sleeper thread should catch all PingPong exceptions and never let any one of them through.
(c) is wrong, throwTo may block, and blocking operations are interruptible.
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception...
explains this in some more detail.
The simplest way that throwTo can actually block in your program, as far as I can see, and one that will only affect the threaded RTS, is if the sleeper thread and whichever thread is running the other throwBack are executing on different capabilities; this will always cause throwTo to block. (You could try looking at a ghc event log to find out more.)
I last ran into trouble like that with System.Timeout.timeout; for that function I finally convinced myself that uninterruptibleMask is the only way to avoid such problems; then throwTo will not be interrupted by exceptions even when it blocks. Maybe this is the solution for your problem, too.
Hope that helps,
Bertram
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
-- Felipe.
participants (3)
-
Bertram Felgenhauer
-
Edward Z. Yang
-
Felipe Almeida Lessa