[project @ 2001-06-28 14:15:04 by simonmar]
[ghc-base.git] / GHC / TopHandler.lhs
1 -- -----------------------------------------------------------------------------
2 -- $Id: TopHandler.lhs,v 1.1 2001/06/28 14:15:03 simonmar Exp $
3 --
4 -- (c) The University of Glasgow, 2001
5 --
6 -- GHC.TopHandler
7 --
8 -- 'Top-level' IO actions want to catch exceptions (e.g., forkIO and 
9 -- GHC.Main.mainIO) and report them - topHandler is the exception
10 -- handler they should use for this:
11
12 -- make sure we handle errors while reporting the error!
13 -- (e.g. evaluating the string passed to 'error' might generate
14 --  another error, etc.)
15
16 -- These functions can't go in GHC.Main, because GHC.Main isn't
17 -- included in HSstd.o (because GHC.Main depends on Main, which
18 -- doesn't exist yet...).
19
20 \begin{code}
21 module GHC.TopHandler (
22    topHandler, reportStackOverflow, reportError 
23   ) where
24
25 import Prelude
26
27 import System.IO
28
29 import Foreign.C.String
30 import Foreign.Ptr
31 import GHC.IOBase
32 import GHC.Exception
33
34 topHandler :: Exception -> IO ()
35 topHandler err = catchException (real_handler err) topHandler
36
37 real_handler :: Exception -> IO ()
38 real_handler ex =
39   case ex of
40         AsyncException StackOverflow -> reportStackOverflow True
41
42         -- only the main thread gets ExitException exceptions
43         ExitException ExitSuccess     -> shutdownHaskellAndExit 0
44         ExitException (ExitFailure n) -> shutdownHaskellAndExit n
45
46         ErrorCall s -> reportError True s
47         other       -> reportError True (showsPrec 0 other "\n")
48
49 -- NOTE: shutdownHaskellAndExit must be called "safe", because it *can*
50 -- re-enter Haskell land through finalizers.
51 foreign import ccall "shutdownHaskellAndExit" 
52   shutdownHaskellAndExit :: Int -> IO ()
53
54 reportStackOverflow :: Bool -> IO ()
55 reportStackOverflow bombOut = do
56    (hFlush stdout) `catchException` (\ _ -> return ())
57    callStackOverflowHook
58    if bombOut then
59      stg_exit 2
60     else
61      return ()
62
63 reportError :: Bool -> String -> IO ()
64 reportError bombOut str = do
65    (hFlush stdout) `catchException` (\ _ -> return ())
66    withCStringLen str $ \(cstr,len) -> do
67      writeErrString addrOf_ErrorHdrHook cstr len
68      if bombOut 
69         then stg_exit 1
70         else return ()
71
72 foreign import ccall "addrOf_ErrorHdrHook" unsafe
73         addrOf_ErrorHdrHook :: Ptr ()
74
75 foreign import ccall "writeErrString__" unsafe
76         writeErrString :: Ptr () -> CString -> Int -> IO ()
77
78 -- SUP: Are the hooks allowed to re-enter Haskell land?  If so, remove
79 -- the unsafe below.
80 foreign import ccall "stackOverflow" unsafe
81         callStackOverflowHook :: IO ()
82
83 foreign import ccall "stg_exit" unsafe
84         stg_exit :: Int -> IO ()
85 \end{code}