[Haskell-cafe] Re: Asynchronous exception wormholes kill modularity

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Fri Apr 9 07:14:49 EDT 2010


Simon Marlow wrote:
> On 09/04/2010 09:40, Bertram Felgenhauer wrote:
> >Simon Marlow wrote:
> >>mask :: ((IO a ->  IO a) ->  IO b) ->  IO b
> >
> >How does forkIO fit into the picture? That's one point where reasonable
> >code may want to unblock all exceptions unconditionally - for example to
> >allow the thread to be killed later.
> 
> Sure, and it works exactly as before in that the new thread inherits
> the masking state of its parent thread.  To unmask exceptions in the
> child thread you need to use the restore operator passed to the
> argument of mask.
> 
> This does mean that if you fork a thread inside mask and don't pass
> it the restore operation, then it has no way to ever unmask
> exceptions.  At worst, this means you have to pass a restore value
> around where you didn't previously.
> 
> >     timeout t io = block $ do
> >         result <- newEmptyMVar
> >         tid <- forkIO $ unblock (io >>= putMVar result)
> >         threadDelay t `onException` killThread tid
> >         killThread tid
> >         tryTakeMVar result
> 
> This would be written
> 
> >      timeout t io = mask $ \restore -> do
> >          result <- newEmptyMVar
> >          tid <- forkIO $ restore (io >>= putMVar result)
> >          threadDelay t `onException` killThread tid
> >          killThread tid
> >          tryTakeMVar result

I'm worried about the case when this function is called with exceptions
already blocked. Then 'restore' will be the identity, and exceptions
will continue to be blocked inside the forked thread.

You could argue that this is the responsibility of the whole chain of
callers (who'd have to supply their own 'restore' functions that will
have to be incorporated into the 'io' action), but that goes against
modularity. In my opinion there's a valid demand for an escape hatch
out of the blocked exception state for newly forked threads.

It could be baked into a variant of the forkIO primitive, say

    forkIOwithUnblock :: ((IO a -> IO a) -> IO b) -> IO ThreadId

Kind regards,

Bertram


More information about the Libraries mailing list