Ticket #4035 (closed proposal: fixed)

Opened 3 years ago

Last modified 3 years ago

Asynchronous exception wormholes kill modularity

Reported by: basvandijk Owned by: simonmar
Priority: high Milestone: 7.0.1
Component: libraries/base Version: 6.12.2
Keywords: Cc: iavor.diatchki@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Difficulty:
Test Case: Blocked By:
Blocking: Related Tickets:

Description

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  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  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)

Change History

Changed 3 years ago by diatchki

  • cc iavor.diatchki@… added

Changed 3 years ago by simonmar

  • owner set to simonmar

Changed 3 years ago by simonmar

  • priority changed from normal to high
  • milestone set to 6.14.1

Changed 3 years ago by simonmar

  • status changed from new to closed
  • resolution set to fixed

Fixed; see #1036.

Note: See TracTickets for help on using tickets.