[project @ 2005-01-28 23:33:57 by krasimir]
[ghc-base.git] / Control / Exception.hs
index 087f6fd..83f37cb 100644 (file)
@@ -105,14 +105,20 @@ module Control.Exception (
        bracket_,       -- :: IO a -> IO b -> IO c -> IO ()
 
        finally,        -- :: IO a -> IO b -> IO a
-
+       
+#ifdef __GLASGOW_HASKELL__
+       setUncaughtExceptionHandler,      -- :: (Exception -> IO ()) -> IO ()
+       getUncaughtExceptionHandler       -- :: IO (Exception -> IO ())
+#endif
   ) 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 Data.IORef      ( IORef, newIORef, readIORef, writeIORef )
+import Foreign.C.String ( CString, withCString )
+import System.IO       ( stdout, hFlush )
 #endif
 
 #ifdef __HUGS__
@@ -163,13 +169,12 @@ INSTANCE_TYPEABLE0(AsyncException,asyncExceptionTc,"AsyncException")
 -- might be a 'ThreadKilled', for example).  In this case it is usually better
 -- to use 'catchJust' and select the kinds of exceptions to catch.
 --
--- Also note that The "Prelude" also exports a
--- function called 'catch' which has the same type as
--- 'Control.Exception.catch', the difference being that the
--- "Prelude" version only catches the IO and user
+-- Also note that the "Prelude" also exports a function called
+-- 'Prelude.catch' with a similar type to 'Control.Exception.catch',
+-- except that the "Prelude" version only catches the IO and user
 -- families of exceptions (as required by Haskell 98).  We recommend
 -- either hiding the "Prelude" version of
--- 'catch' when importing
+-- 'Prelude.catch' when importing
 -- "Control.Exception", or importing
 -- "Control.Exception" qualified, to avoid name-clashes.
 
@@ -214,25 +219,6 @@ handleJust :: (Exception -> Maybe b) -> (b -> IO a) -> IO a -> IO a
 handleJust p =  flip (catchJust p)
 
 -----------------------------------------------------------------------------
--- evaluate
-
--- | Forces its argument to be evaluated, and returns the result in
--- the 'IO' monad.  It can be used to order evaluation with respect to
--- other 'IO' operations; its semantics are given by
---
--- >   evaluate undefined `seq` return ()  ==> return ()
--- >   catch (evaluate undefined) (\e -> return ())  ==> return ()
---
--- NOTE: @(evaluate a)@ is /not/ the same as @(a \`seq\` return a)@.
-#ifdef __GLASGOW_HASKELL__
-evaluate :: a -> IO a
-evaluate a = IO $ \s -> case a `seq` () of () -> (# s, a #)
-       -- NB. can't write  
-       --      a `seq` (# s, a #)
-       -- because we can't have an unboxed tuple as a function argument
-#endif
-
------------------------------------------------------------------------------
 -- 'mapException'
 
 -- | This function maps one exception into another as proposed in the
@@ -248,7 +234,7 @@ mapException f v = unsafePerformIO (catch (evaluate v)
 -- 'try' and variations.
 
 -- | Similar to 'catch', but returns an 'Either' result which is
--- @(Right a)@ if no exception was raised, or @(Left e)@ if an
+-- @('Right' a)@ if no exception was raised, or @('Left' e)@ if an
 -- exception was raised and its value is @e@.
 --
 -- >  try a = catch (Right \`liftM\` a) (return . Left)
@@ -257,6 +243,11 @@ mapException f v = unsafePerformIO (catch (evaluate v)
 -- to re-throw the exception after performing whatever cleanup is needed.
 -- Otherwise, 'tryJust' is generally considered to be better.
 --
+-- Also note that "System.IO.Error" also exports a function called
+-- 'System.IO.Error.try' with a similar type to 'Control.Exception.try',
+-- except that it catches only the IO and user families of exceptions
+-- (as required by the Haskell 98 @IO@ module).
+
 try :: IO a -> IO (Either Exception a)
 try a = catch (a >>= \ v -> return (Right v)) (\e -> return (Left e))
 
@@ -505,3 +496,29 @@ assert :: Bool -> a -> a
 assert True x = x
 assert False _ = throw (AssertionFailed "")
 #endif
+
+
+#ifdef __GLASGOW_HASKELL__
+{-# NOINLINE uncaughtExceptionHandler #-}
+uncaughtExceptionHandler :: IORef (Exception -> IO ())
+uncaughtExceptionHandler = 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"
+         withCString "%s" $ \cfmt ->
+          withCString msg $ \cmsg ->
+            errorBelch cfmt cmsg
+
+foreign import ccall unsafe errorBelch :: CString -> CString -> IO ()
+
+setUncaughtExceptionHandler :: (Exception -> IO ()) -> IO ()
+setUncaughtExceptionHandler = writeIORef uncaughtExceptionHandler
+
+getUncaughtExceptionHandler :: IO (Exception -> IO ())
+getUncaughtExceptionHandler = readIORef uncaughtExceptionHandler
+#endif