mask, catch, myThreadId, throwTo

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Mon Apr 15 22:25:34 CEST 2013


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.html#v:throwTo

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




More information about the Glasgow-haskell-users mailing list