X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=GHC%2FTopHandler.lhs;h=b1ac1b83c2b0e6b0899ddce5caeb8f9cab9f58c6;hb=ce95dd798cdf6068515e4e6e08fb8b3f9d65f79a;hp=884fcf120a6a7d5959b7c18add7e1b6a4b693d9f;hpb=740432bcb906959a6742ddde36946f6737e9447a;p=ghc-base.git diff --git a/GHC/TopHandler.lhs b/GHC/TopHandler.lhs index 884fcf1..b1ac1b8 100644 --- a/GHC/TopHandler.lhs +++ b/GHC/TopHandler.lhs @@ -14,8 +14,9 @@ -- ----------------------------------------------------------------------------- +-- #hide module GHC.TopHandler ( - runIO, runNonIO, reportStackOverflow, reportError + runMainIO, runIO, runNonIO, reportStackOverflow, reportError ) where import Prelude @@ -23,17 +24,21 @@ import Prelude import System.IO import Control.Exception -import Foreign.C.String -import Foreign.Ptr import GHC.IOBase import GHC.Exception import GHC.Prim (unsafeCoerce#) --- | 'runIO' is wrapped around @Main.main@ by @TcModule@. It is also wrapped --- around every @foreign export@ and @foreign import \"wrapper\"@ to mop up --- any uncaught exceptions. Thus, the result of running --- 'System.Exit.exitWith' in a foreign-exported function is the same as --- in the main thread: it terminates the program. +-- | 'runMainIO' is wrapped around 'Main.main' (or whatever main is +-- called in the program). It catches otherwise uncaught exceptions, +-- and also flushes stdout\/stderr before exiting. +runMainIO :: IO a -> IO a +runMainIO main = (do a <- main; cleanUp; return a) `catchException` topHandler + +-- | 'runIO' is wrapped around every @foreign export@ and @foreign +-- import \"wrapper\"@ to mop up any uncaught exceptions. Thus, the +-- result of running 'System.Exit.exitWith' in a foreign-exported +-- function is the same as in the main thread: it terminates the +-- program. -- runIO :: IO a -> IO a runIO main = catchException main topHandler @@ -54,50 +59,53 @@ topHandler err = catchException (real_handler err) topHandler -- real_handler :: Exception -> IO a real_handler ex = + cleanUp >> case ex of - AsyncException StackOverflow -> reportStackOverflow True + AsyncException StackOverflow -> do + reportStackOverflow + safeExit 2 -- only the main thread gets ExitException exceptions - ExitException ExitSuccess -> safe_exit 0 - ExitException (ExitFailure n) -> safe_exit n + ExitException ExitSuccess -> safeExit 0 + ExitException (ExitFailure n) -> safeExit n - other -> reportError True other + other -> do + reportError other + safeExit 1 -reportStackOverflow :: Bool -> IO a -reportStackOverflow bombOut = do - (hFlush stdout) `catchException` (\ _ -> return ()) - callStackOverflowHook - if bombOut - then exit 2 - else return undefined - -reportError :: Bool -> Exception -> IO a -reportError bombOut ex = do - handler <- getUncatchedExceptionHandler +reportStackOverflow :: IO a +reportStackOverflow = do callStackOverflowHook; return undefined + +reportError :: Exception -> IO a +reportError ex = do + handler <- getUncaughtExceptionHandler handler ex - if bombOut - then exit 1 - else return undefined + return undefined -- SUP: Are the hooks allowed to re-enter Haskell land? If so, remove -- the unsafe below. foreign import ccall unsafe "stackOverflow" callStackOverflowHook :: IO () -foreign import ccall unsafe "stg_exit" - stg_exit :: Int -> IO () +-- try to flush stdout/stderr, but don't worry if we fail +-- (these handles might have errors, and we don't want to go into +-- an infinite loop). +cleanUp :: IO () +cleanUp = do + hFlush stdout `catchException` \_ -> return () + hFlush stderr `catchException` \_ -> return () + +cleanUpAndExit :: Int -> IO a +cleanUpAndExit r = do cleanUp; safeExit r -exit :: Int -> IO a -exit r = unsafeCoerce# (stg_exit r) +-- we have to use unsafeCoerce# to get the 'IO a' result type, since the +-- compiler doesn't let us declare that as the result type of a foreign export. +safeExit :: Int -> IO a +safeExit r = unsafeCoerce# (shutdownHaskellAndExit r) -- NOTE: shutdownHaskellAndExit must be called "safe", because it *can* -- re-enter Haskell land through finalizers. foreign import ccall "shutdownHaskellAndExit" shutdownHaskellAndExit :: Int -> IO () - --- we have to use unsafeCoerce# to get the 'IO a' result type, since the --- compiler doesn't let us declare that as the result type of a foreign export. -safe_exit :: Int -> IO a -safe_exit r = unsafeCoerce# (shutdownHaskellAndExit r) \end{code}