diff options
author | Zubin Duggal <zubin@cmi.ac.in> | 2021-02-21 02:36:48 +0530 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-02-27 08:00:46 -0500 |
commit | 902ece87ffac545451c2a66d145e6c8653e12092 (patch) | |
tree | 8855c339d4a86ebd3577d893b07a62f26acfa99a /compiler/GHC/Data | |
parent | df6d42d0c2534fe620798aab01a393dbd40573fb (diff) | |
download | haskell-902ece87ffac545451c2a66d145e6c8653e12092.tar.gz |
switch to using forkIO to detect async exceptions
Diffstat (limited to 'compiler/GHC/Data')
-rw-r--r-- | compiler/GHC/Data/IOEnv.hs | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/compiler/GHC/Data/IOEnv.hs b/compiler/GHC/Data/IOEnv.hs index 7d976b1f82..e438cfaf0d 100644 --- a/compiler/GHC/Data/IOEnv.hs +++ b/compiler/GHC/Data/IOEnv.hs @@ -52,6 +52,8 @@ import GHC.Utils.Monad import GHC.Utils.Logger import Control.Applicative (Alternative(..)) import GHC.Exts( oneShot ) +import Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar) +import Control.Concurrent (forkIO, killThread) ---------------------------------------------------------------------- -- Defining the monad type @@ -168,22 +170,21 @@ tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r) tryAllM (IOEnv thing) = IOEnv (\ env -> safeTry (thing env)) -- | Like 'try', but doesn't catch asynchronous exceptions -safeTry :: Exception e => IO a -> IO (Either e a) -safeTry x = do - r <- try x - case r of - Left e - | isSyncException e -> pure $ Left e - | otherwise -> throwIO e - Right a -> pure $ pure a - --- | Detect if a exception is synchronous --- Taken from safe-exceptions -isSyncException :: Exception e => e -> Bool -isSyncException e = - case fromException (toException e) of - Just (SomeAsyncException _) -> False - Nothing -> True +safeTry :: IO a -> IO (Either SomeException a) +safeTry act = do + var <- newEmptyMVar + uninterruptibleMask $ \restore -> do + -- Fork, so that 'act' is safe from all asynchronous exceptions other than the ones we send it + t <- forkIO $ try (restore act) >>= putMVar var + r <- (restore $ readMVar var) + `catch` \(e :: SomeException) -> do + -- Control reaches this point only if the parent thread was sent an async exception + -- In that case, kill the 'act' thread and re-raise the exception + killThread t + throwIO e + -- cleanup and return + killThread t + pure r tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r) tryMostM (IOEnv thing) = IOEnv (\ env -> tryMost (thing env)) |