id,summary,reporter,owner,description,type,status,priority,milestone,component,version,resolution,keywords,cc,os,architecture,failure,difficulty,testcase,blockedby,blocking,related
4035,Asynchronous exception wormholes kill modularity,basvandijk,simonmar,"Functions like `finally` create, what I call, an asynchronous exception wormhole because they unblock asynchronous exceptions even if you call them in a blocked scope:

{{{
finally :: IO a -> IO b -> IO a
a `finally` sequel = block $ do
  r <- unblock a `onException` sequel
  _ <- sequel
  return r
}}}

This hurts modularity.

I [http://www.haskell.org/pipermail/libraries/2010-March/013310.html proposed] solving this as follows:

{{{
finally :: IO a -> IO b -> IO a
a `finally` sequel = do 
  b <- blocked
  block $ do
    r <- (if b then unblock a else a) `onException` sequel
    _ <- sequel
    return r
}}}

Besides `finally` the following functions also have a wormhole:

 * Control.Exception.'''finally'''/'''bracket'''/'''bracketOnError'''
 * Control.Concurrent.MVar.'''withMVar'''/'''modifyMVar_'''/'''modifyMVar'''
 * Foreign.Marshal.Pool.'''withPool'''

In the interesting discussion that followed several other solutions were proposed (for example a block and unblock that count nesting levels). 

Later, Simon Marlow [http://www.haskell.org/pipermail/libraries/2010-April/013420.html proposed] an even nicer solution:

{{{
mask :: ((IO a -> IO a) -> IO b) -> IO b
mask io = do
   b <- blocked
   if b
      then io id
      else block $ io unblock
}}}

to be used like this:

{{{
a `finally` sequel =
   mask $ \restore -> do
     r <- restore a `onException` sequel
     sequel
     return r
}}}

I created this ticket so we won't forget about this problem.

(These are related bugs: #3944 and #3945)",proposal,closed,high,7.0.1,libraries/base,6.12.2,fixed,,iavor.diatchki@…,Unknown/Multiple,Unknown/Multiple,None/Unknown,,,,,
