Added interface to set/get handler for uncatched exceptions.
The handler is invoked from the GHC.TopHandler.topHandler or
Control.Concurrent.childHandler when an exception is catched.
-- report all others:
AsyncException StackOverflow -> reportStackOverflow False
- ErrorCall s -> reportError False s
- other -> reportError False (showsPrec 0 other "\n")
+ other -> reportError False other
#endif /* __GLASGOW_HASKELL__ */
bracket_, -- :: IO a -> IO b -> IO c -> IO ()
finally, -- :: IO a -> IO b -> IO a
-
+
+ setUncatchedExceptionHandler, -- :: (Exception -> IO ()) -> IO ()
+ getUncatchedExceptionHandler -- :: IO (Exception -> IO ())
) where
#ifdef __GLASGOW_HASKELL__
import GHC.Base ( assert )
import GHC.Exception as ExceptionBase hiding (catch)
import GHC.Conc ( throwTo, ThreadId )
-import GHC.IOBase ( IO(..) )
+import GHC.IOBase ( IO(..), IORef(..), newIORef, readIORef, writeIORef )
+import GHC.Handle ( stdout, hFlush )
+import Foreign.C.String ( CString, withCStringLen )
#endif
#ifdef __HUGS__
assert True x = x
assert False _ = throw (AssertionFailed "")
#endif
+
+
+{-# NOINLINE uncatchedExceptionHandler #-}
+uncatchedExceptionHandler :: IORef (Exception -> IO ())
+uncatchedExceptionHandler = unsafePerformIO (newIORef defaultHandler)
+ where
+ defaultHandler :: Exception -> IO ()
+ defaultHandler ex = do
+ (hFlush stdout) `catchException` (\ _ -> return ())
+ let msg = case ex of
+ Deadlock -> "no threads to run: infinite loop or deadlock?"
+ ErrorCall s -> s
+ other -> showsPrec 0 other "\n"
+ withCStringLen ("Fail: "++msg) $ \(cstr,len) -> writeErrString cstr len
+
+foreign import ccall unsafe "writeErrString__"
+ writeErrString :: CString -> Int -> IO ()
+
+setUncatchedExceptionHandler :: (Exception -> IO ()) -> IO ()
+setUncatchedExceptionHandler = writeIORef uncatchedExceptionHandler
+
+getUncatchedExceptionHandler :: IO (Exception -> IO ())
+getUncatchedExceptionHandler = readIORef uncatchedExceptionHandler
-----------------------------------------------------------------------------
module GHC.TopHandler (
- runIO, runNonIO, reportStackOverflow, reportError
+ runIO, runNonIO, reportStackOverflow, reportError
) where
import Prelude
import System.IO
+import Control.Exception
import Foreign.C.String
import Foreign.Ptr
ExitException ExitSuccess -> safe_exit 0
ExitException (ExitFailure n) -> safe_exit n
- Deadlock -> reportError True
- "no threads to run: infinite loop or deadlock?"
-
- ErrorCall s -> reportError True s
- other -> reportError True (showsPrec 0 other "\n")
+ other -> reportError True other
+
reportStackOverflow :: Bool -> IO a
reportStackOverflow bombOut = do
then exit 2
else return undefined
-reportError :: Bool -> String -> IO a
-reportError bombOut str = do
- (hFlush stdout) `catchException` (\ _ -> return ())
- withCStringLen str $ \(cstr,len) -> do
- writeErrString errorHdrHook cstr len
- if bombOut
- then exit 1
- else return undefined
-
-#ifndef ILX
-foreign import ccall "&ErrorHdrHook" errorHdrHook :: Ptr ()
-#else
-foreign import ccall "ErrorHdrHook" errorHdrHook :: Ptr ()
-#endif
-
-foreign import ccall unsafe "writeErrString__"
- writeErrString :: Ptr () -> CString -> Int -> IO ()
+reportError :: Bool -> Exception -> IO a
+reportError bombOut ex = do
+ handler <- getUncatchedExceptionHandler
+ 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.
-/*
+/*
* (c) The University of Glasgow 2002
*
- * $Id: writeError.c,v 1.5 2002/02/07 11:13:30 simonmar Exp $
+ * $Id: writeError.c,v 1.6 2004/02/12 21:23:49 krasimir Exp $
*
* hPutStr Runtime Support
*/
#include "HsBase.h"
void
-writeErrString__(HsAddr msg_hdr, HsAddr msg, HsInt len)
+writeErrString__(HsAddr msg, HsInt len)
{
int count = 0;
char* p = (char*)msg;
resetNonBlockingFd(2);
#endif
- /* Print error msg header */
- if (msg_hdr) {
- ((void (*)(int))msg_hdr)(2/*stderr*/);
- }
-
while ( (count = write(2,p,len)) < len) {
if (errno != EINTR ) {
return;
int inputReady(int fd, int msecs, int isSock);
/* in writeError.c */
-void writeErrString__(HsAddr msg_hdr, HsAddr msg, HsInt len);
+void writeErrString__(HsAddr msg, HsInt len);
/* in Signals.c */
extern HsInt nocldstop;
return setmode(fd,(toBin == HS_BOOL_TRUE) ? _O_BINARY : _O_TEXT);
#else
return 0;
-#endif
+#endif
}
INLINE HsInt
#if !defined(_MSC_VER)
INLINE HsAddr
__hscore_d_name( struct dirent* d )
-{
+{
#if !defined(mingw32_TARGET_OS) && !defined(_MSC_VER)
return (HsAddr)(&d->d_name);
#else
return 0;
#else
return ENOENT;
-#endif
+#endif
}
INLINE void
__hscore_poke_lflag( struct termios* ts, tcflag_t t ) { ts->c_lflag = t; }
INLINE unsigned char*
-__hscore_ptr_c_cc( struct termios* ts )
+__hscore_ptr_c_cc( struct termios* ts )
{ return (unsigned char*) &ts->c_cc; }
INLINE HsInt