[commit: ghc] master: Mask async exceptions in forkM_ (586bc85)

git at git.haskell.org git at git.haskell.org
Tue Dec 3 16:51:23 UTC 2013


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/586bc85538cf12048137c2693da7c9fe3ca481ef/ghc

>---------------------------------------------------------------

commit 586bc85538cf12048137c2693da7c9fe3ca481ef
Author: Edsko de Vries <edsko at well-typed.com>
Date:   Thu Nov 28 16:38:26 2013 +0000

    Mask async exceptions in forkM_
    
    See #8006 for the reason why. This is not a fix as such; more of a workaround.


>---------------------------------------------------------------

586bc85538cf12048137c2693da7c9fe3ca481ef
 compiler/typecheck/TcRnMonad.lhs |   19 ++++++++++++++++++-
 compiler/utils/IOEnv.hs          |    4 +++-
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/compiler/typecheck/TcRnMonad.lhs b/compiler/typecheck/TcRnMonad.lhs
index cf8298f..d5a9383 100644
--- a/compiler/typecheck/TcRnMonad.lhs
+++ b/compiler/typecheck/TcRnMonad.lhs
@@ -1314,7 +1314,8 @@ forkM_maybe doc thing_inside
  --     does not get updated atomically (e.g. in newUnique and newUniqueSupply).
  = do { child_us <- newUniqueSupply
       ; child_env_us <- newMutVar child_us
-      ; unsafeInterleaveM $ updEnv (\env -> env { env_us = child_env_us }) $
+        -- see Note [Masking exceptions in forkM_maybe]
+      ; unsafeInterleaveM $ uninterruptibleMaskM_ $ updEnv (\env -> env { env_us = child_env_us }) $
         do { traceIf (text "Starting fork {" <+> doc)
            ; mb_res <- tryM $
                        updLclEnv (\env -> env { if_loc = if_loc env $$ doc }) $
@@ -1345,3 +1346,19 @@ forkM doc thing_inside
                                    -- pprPanic "forkM" doc
                         Just r  -> r) }
 \end{code}
+
+Note [Masking exceptions in forkM_maybe]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using GHC-as-API it must be possible to interrupt snippets of code
+executed using runStmt (#1381). Since commit 02c4ab04 this is almost possible
+by throwing an asynchronous interrupt to the GHC thread. However, there is a
+subtle problem: runStmt first typechecks the code before running it, and the
+exception might interrupt the type checker rather than the code. Moreover, the
+typechecker might be inside an unsafeInterleaveIO (through forkM_maybe), and
+more importantly might be inside an exception handler inside that
+unsafeInterleaveIO. If that is the case, the exception handler will rethrow the
+asynchronous exception as a synchronous exception, and the exception will end
+up as the value of the unsafeInterleaveIO thunk (see #8006 for a detailed
+discussion).  We don't currently know a general solution to this problem, but
+we can use uninterruptibleMask_ to avoid the situation. 
diff --git a/compiler/utils/IOEnv.hs b/compiler/utils/IOEnv.hs
index 04c11cf..6885bbd 100644
--- a/compiler/utils/IOEnv.hs
+++ b/compiler/utils/IOEnv.hs
@@ -22,7 +22,7 @@ module IOEnv (
         -- Getting at the environment
         getEnv, setEnv, updEnv,
 
-        runIOEnv, unsafeInterleaveM,
+        runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,
         tryM, tryAllM, tryMostM, fixM,
 
         -- I/O operations
@@ -149,6 +149,8 @@ tryMostM (IOEnv thing) = IOEnv (\ env -> tryMost (thing env))
 unsafeInterleaveM :: IOEnv env a -> IOEnv env a
 unsafeInterleaveM (IOEnv m) = IOEnv (\ env -> unsafeInterleaveIO (m env))
 
+uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
+uninterruptibleMaskM_ (IOEnv m) = IOEnv (\ env -> uninterruptibleMask_ (m env))
 
 ----------------------------------------------------------------------
 -- Alternative/MonadPlus



More information about the ghc-commits mailing list