X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=GHC%2FTopHandler.lhs;h=8c123a228412bb58f9d80550a63a3239fd62e21b;hb=ed813264145aa7d96c44375c8d92c93e3b1a4539;hp=344a856038059090f99157665ab013e2faeb3745;hpb=3d39b8130899c46c9c96b941fddb4e4784e860dc;p=ghc-base.git diff --git a/GHC/TopHandler.lhs b/GHC/TopHandler.lhs index 344a856..8c123a2 100644 --- a/GHC/TopHandler.lhs +++ b/GHC/TopHandler.lhs @@ -1,88 +1,103 @@ --- ----------------------------------------------------------------------------- --- $Id: TopHandler.lhs,v 1.3 2001/08/17 12:50:34 simonmar Exp $ --- --- (c) The University of Glasgow, 2001 +\begin{code} +----------------------------------------------------------------------------- +-- | +-- Module : GHC.TopHandler +-- Copyright : (c) The University of Glasgow, 2001-2002 +-- License : see libraries/base/LICENSE +-- +-- Maintainer : cvs-ghc@haskell.org +-- Stability : internal +-- Portability : non-portable (GHC Extensions) -- --- GHC.TopHandler +-- Support for catching exceptions raised during top-level computations +-- (e.g. @Main.main@, 'Control.Concurrent.forkIO', and foreign exports) -- --- 'Top-level' IO actions want to catch exceptions (e.g., forkIO and --- GHC.Main.mainIO) and report them - topHandler is the exception --- handler they should use for this: - --- make sure we handle errors while reporting the error! --- (e.g. evaluating the string passed to 'error' might generate --- another error, etc.) - --- These functions can't go in GHC.Main, because GHC.Main isn't --- included in HSstd.o (because GHC.Main depends on Main, which --- doesn't exist yet...). +----------------------------------------------------------------------------- -\begin{code} module GHC.TopHandler ( - topHandler, reportStackOverflow, reportError + runIO, runNonIO, reportStackOverflow, reportError ) where 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#) -topHandler :: Exception -> IO () +-- | '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. +-- +runIO :: IO a -> IO a +runIO main = catchException main topHandler + +-- | The same as 'runIO', but for non-IO computations. Used for +-- wrapping @foreign export@ and @foreign import \"wrapper\"@ when these +-- are used to export Haskell functions with non-IO types. +-- +runNonIO :: a -> IO a +runNonIO a = catchException (a `seq` return a) topHandler + +topHandler :: Exception -> IO a topHandler err = catchException (real_handler err) topHandler -real_handler :: Exception -> IO () +-- Make sure we handle errors while reporting the error! +-- (e.g. evaluating the string passed to 'error' might generate +-- another error, etc.) +-- +real_handler :: Exception -> IO a real_handler ex = case ex of AsyncException StackOverflow -> reportStackOverflow True -- only the main thread gets ExitException exceptions - ExitException ExitSuccess -> shutdownHaskellAndExit 0 - ExitException (ExitFailure n) -> shutdownHaskellAndExit n - - ErrorCall s -> reportError True s - other -> reportError True (showsPrec 0 other "\n") + ExitException ExitSuccess -> safe_exit 0 + ExitException (ExitFailure n) -> safe_exit n --- NOTE: shutdownHaskellAndExit must be called "safe", because it *can* --- re-enter Haskell land through finalizers. -foreign import ccall "shutdownHaskellAndExit" - shutdownHaskellAndExit :: Int -> IO () + other -> reportError True other + -reportStackOverflow :: Bool -> IO () +reportStackOverflow :: Bool -> IO a reportStackOverflow bombOut = do (hFlush stdout) `catchException` (\ _ -> return ()) callStackOverflowHook - if bombOut then - stg_exit 2 - else - return () - -reportError :: Bool -> String -> IO () -reportError bombOut str = do - (hFlush stdout) `catchException` (\ _ -> return ()) - withCStringLen str $ \(cstr,len) -> do - writeErrString errorHdrHook cstr len - if bombOut - then stg_exit 1 - else return () - -#ifndef ILX -foreign label "ErrorHdrHook" errorHdrHook :: Ptr () -#else -foreign import "ErrorHdrHook" errorHdrHook :: Ptr () -#endif - -foreign import ccall "writeErrString__" unsafe - writeErrString :: Ptr () -> CString -> Int -> IO () + if bombOut + then exit 2 + else return undefined + +reportError :: Bool -> Exception -> IO a +reportError bombOut ex = do + handler <- getUncaughtExceptionHandler + handler ex + if bombOut + then exit 1 + else return undefined -- SUP: Are the hooks allowed to re-enter Haskell land? If so, remove -- the unsafe below. -foreign import ccall "stackOverflow" unsafe +foreign import ccall unsafe "stackOverflow" callStackOverflowHook :: IO () -foreign import ccall "stg_exit" unsafe +foreign import ccall unsafe "stg_exit" stg_exit :: Int -> IO () + +exit :: Int -> IO a +exit r = unsafeCoerce# (stg_exit 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}