{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# OPTIONS_HADDOCK not-home #-}
module GHC.TopHandler (
runMainIO, runIO, runIOFastExit, runNonIO,
topHandler, topHandlerFastExit,
reportStackOverflow, reportError,
flushStdHandles
) where
#include <ghcplatform.h>
#include "HsBaseConfig.h"
import Control.Exception
import Data.Maybe
import Foreign
import Foreign.C
import GHC.Base
import GHC.Conc hiding (throwTo)
import GHC.Real
import GHC.IO
import GHC.IO.Handle
import GHC.IO.StdHandles
import GHC.IO.Exception
import GHC.Weak
#if defined(mingw32_HOST_OS)
import GHC.ConsoleHandler
#elif defined(js_HOST_ARCH)
#else
import Data.Dynamic (toDyn)
#endif
foreign import ccall unsafe "rts_setMainThread"
setMainThread :: Weak# ThreadId -> IO ()
runMainIO :: IO a -> IO a
runMainIO :: forall a. IO a -> IO a
runMainIO IO a
main =
do
ThreadId
main_thread_id <- IO ThreadId
myThreadId
Weak ThreadId
weak_tid <- ThreadId -> IO (Weak ThreadId)
mkWeakThreadId ThreadId
main_thread_id
(SomeException -> IO ()) -> IO ()
setFinalizerExceptionHandler SomeException -> IO ()
handleFinalizerException
case Weak ThreadId
weak_tid of (Weak Weak# ThreadId
w) -> Weak# ThreadId -> IO ()
setMainThread Weak# ThreadId
w
IO () -> IO ()
install_interrupt_handler (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Maybe ThreadId
m <- Weak ThreadId -> IO (Maybe ThreadId)
forall v. Weak v -> IO (Maybe v)
deRefWeak Weak ThreadId
weak_tid
case Maybe ThreadId
m of
Maybe ThreadId
Nothing -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just ThreadId
tid -> ThreadId -> SomeException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
tid (AsyncException -> SomeException
forall e. Exception e => e -> SomeException
toException AsyncException
UserInterrupt)
IO a
main
IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch`
SomeException -> IO a
forall a. SomeException -> IO a
topHandler
install_interrupt_handler :: IO () -> IO ()
#if defined(js_HOST_ARCH)
install_interrupt_handler _ = return ()
#elif defined(mingw32_HOST_OS)
install_interrupt_handler handler = do
_ <- GHC.ConsoleHandler.installHandler $
Catch $ \event ->
case event of
ControlC -> handler
Break -> handler
Close -> handler
_ -> return ()
return ()
#elif !defined(HAVE_SIGNAL_H)
install_interrupt_handler _ = pure ()
#else
#include "rts/Signals.h"
install_interrupt_handler :: IO () -> IO ()
install_interrupt_handler IO ()
handler = do
let sig :: CInt
sig = CONST_SIGINT :: CInt
Maybe (HandlerFun, Dynamic)
_ <- CInt
-> Maybe (HandlerFun, Dynamic) -> IO (Maybe (HandlerFun, Dynamic))
setHandler CInt
sig ((HandlerFun, Dynamic) -> Maybe (HandlerFun, Dynamic)
forall a. a -> Maybe a
Just (IO () -> HandlerFun
forall a b. a -> b -> a
const IO ()
handler, IO () -> Dynamic
forall a. Typeable a => a -> Dynamic
toDyn IO ()
handler))
CInt
_ <- CInt -> CInt -> Ptr () -> IO CInt
stg_sig_install CInt
sig STG_SIG_RST nullPtr
() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
foreign import ccall unsafe
stg_sig_install
:: CInt
-> CInt
-> Ptr ()
-> IO CInt
#endif
runIO :: IO a -> IO a
runIO :: forall a. IO a -> IO a
runIO IO a
main = IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch IO a
main SomeException -> IO a
forall a. SomeException -> IO a
topHandler
runIOFastExit :: IO a -> IO a
runIOFastExit :: forall a. IO a -> IO a
runIOFastExit IO a
main = IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch IO a
main SomeException -> IO a
forall a. SomeException -> IO a
topHandlerFastExit
runNonIO :: a -> IO a
runNonIO :: forall a. a -> IO a
runNonIO a
a = IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (a
a a -> IO a -> IO a
forall a b. a -> b -> b
`seq` a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a) SomeException -> IO a
forall a. SomeException -> IO a
topHandler
topHandler :: SomeException -> IO a
topHandler :: forall a. SomeException -> IO a
topHandler SomeException
err = IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch ((Int -> IO a) -> SomeException -> IO a
forall a. (Int -> IO a) -> SomeException -> IO a
real_handler Int -> IO a
forall a. Int -> IO a
safeExit SomeException
err) SomeException -> IO a
forall a. SomeException -> IO a
topHandler
topHandlerFastExit :: SomeException -> IO a
topHandlerFastExit :: forall a. SomeException -> IO a
topHandlerFastExit SomeException
err =
IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catchException ((Int -> IO a) -> SomeException -> IO a
forall a. (Int -> IO a) -> SomeException -> IO a
real_handler Int -> IO a
forall a. Int -> IO a
fastExit SomeException
err) SomeException -> IO a
forall a. SomeException -> IO a
topHandlerFastExit
real_handler :: (Int -> IO a) -> SomeException -> IO a
real_handler :: forall a. (Int -> IO a) -> SomeException -> IO a
real_handler Int -> IO a
exit SomeException
se = do
IO ()
flushStdHandles
case SomeException -> Maybe AsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
Just AsyncException
StackOverflow -> do
IO ()
reportStackOverflow
Int -> IO a
exit Int
2
Just AsyncException
UserInterrupt -> IO a
forall a. IO a
exitInterrupted
Just AsyncException
HeapOverflow -> do
IO ()
reportHeapOverflow
Int -> IO a
exit Int
251
Maybe AsyncException
_ -> case SomeException -> Maybe ExitCode
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
Just ExitCode
ExitSuccess -> Int -> IO a
exit Int
0
Just (ExitFailure Int
n) -> Int -> IO a
exit Int
n
Maybe ExitCode
_ -> IO a -> (IOError -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (case SomeException -> Maybe IOError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
Just IOError{ ioe_type :: IOError -> IOErrorType
ioe_type = IOErrorType
ResourceVanished,
ioe_errno :: IOError -> Maybe CInt
ioe_errno = Just CInt
ioe,
ioe_handle :: IOError -> Maybe Handle
ioe_handle = Just Handle
hdl }
| CInt -> Errno
Errno CInt
ioe Errno -> Errno -> Bool
forall a. Eq a => a -> a -> Bool
== Errno
ePIPE, Handle
hdl Handle -> Handle -> Bool
forall a. Eq a => a -> a -> Bool
== Handle
stdout -> Int -> IO a
exit Int
0
Maybe IOError
_ -> do SomeException -> IO ()
reportError SomeException
se
Int -> IO a
exit Int
1
) ((Int -> IO a) -> IOError -> IO a
forall a. (Int -> IO a) -> IOError -> IO a
disasterHandler Int -> IO a
exit)
foreign import ccall unsafe "HsBase.h errorBelch2"
errorBelch :: CString -> CString -> IO ()
disasterHandler :: (Int -> IO a) -> IOError -> IO a
disasterHandler :: forall a. (Int -> IO a) -> IOError -> IO a
disasterHandler Int -> IO a
exit IOError
_ =
String -> (CString -> IO a) -> IO a
forall a. String -> (CString -> IO a) -> IO a
withCAString String
"%s" ((CString -> IO a) -> IO a) -> (CString -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \CString
fmt ->
String -> (CString -> IO a) -> IO a
forall a. String -> (CString -> IO a) -> IO a
withCAString String
msgStr ((CString -> IO a) -> IO a) -> (CString -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \CString
msg ->
CString -> CString -> IO ()
errorBelch CString
fmt CString
msg IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> IO a
exit Int
1
where
msgStr :: String
msgStr =
String
"encountered an exception while trying to report an exception.\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"One possible reason for this is that we failed while trying to " String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"encode an error message. Check that your locale is configured " String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"properly."
flushStdHandles :: IO ()
flushStdHandles :: IO ()
flushStdHandles = do
Handle -> IO ()
hFlush Handle
stdout IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` SomeException -> IO ()
handleExc
Handle -> IO ()
hFlush Handle
stderr IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` SomeException -> IO ()
handleExc
where
handleExc :: SomeException -> IO ()
handleExc SomeException
se = do
SomeException -> IO ()
handleFinalizerExc <- IO (SomeException -> IO ())
getFinalizerExceptionHandler
SomeException -> IO ()
handleFinalizerExc SomeException
se IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` (\(SomeException e
_) -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
handleFinalizerException :: SomeException -> IO ()
handleFinalizerException :: SomeException -> IO ()
handleFinalizerException SomeException
se =
Handle -> String -> IO ()
hPutStr Handle
stderr String
msg IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` (\(SomeException e
_) -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
where
msg :: String
msg = String
"Exception during Weak# finalization (ignored): " String -> String -> String
forall a. [a] -> [a] -> [a]
++ SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
se String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"
safeExit, fastExit :: Int -> IO a
safeExit :: forall a. Int -> IO a
safeExit = CInt -> Int -> IO a
forall a. CInt -> Int -> IO a
exitHelper CInt
useSafeExit
fastExit :: forall a. Int -> IO a
fastExit = CInt -> Int -> IO a
forall a. CInt -> Int -> IO a
exitHelper CInt
useFastExit
unreachable :: IO a
unreachable :: forall a. IO a
unreachable = String -> IO a
forall a. String -> IO a
failIO String
"If you can read this, shutdownHaskellAndExit did not exit."
exitHelper :: CInt -> Int -> IO a
#if defined(mingw32_HOST_OS) || defined(js_HOST_ARCH)
exitHelper exitKind r =
shutdownHaskellAndExit (fromIntegral r) exitKind >> unreachable
#else
exitHelper :: forall a. CInt -> Int -> IO a
exitHelper CInt
exitKind Int
r
| Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
255
= CInt -> CInt -> IO ()
shutdownHaskellAndExit (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
r) CInt
exitKind IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO a
forall a. IO a
unreachable
| Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= -Int
127 Bool -> Bool -> Bool
&& Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= -Int
1
= CInt -> CInt -> IO ()
shutdownHaskellAndSignal (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (-Int
r)) CInt
exitKind IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO a
forall a. IO a
unreachable
| Bool
otherwise
= CInt -> CInt -> IO ()
shutdownHaskellAndExit CInt
0xff CInt
exitKind IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO a
forall a. IO a
unreachable
#if !defined(HAVE_SIGNAL_H)
shutdownHaskellAndSignal :: CInt -> CInt -> IO ()
shutdownHaskellAndSignal = shutdownHaskellAndExit
#else
foreign import ccall "shutdownHaskellAndSignal"
shutdownHaskellAndSignal :: CInt -> CInt -> IO ()
#endif
#endif
exitInterrupted :: IO a
exitInterrupted :: forall a. IO a
exitInterrupted =
#if defined(mingw32_HOST_OS) || defined(js_HOST_ARCH)
safeExit 252
#elif !defined(HAVE_SIGNAL_H)
safeExit 1
#else
Int -> IO a
forall a. Int -> IO a
safeExit (-CONST_SIGINT)
#endif
foreign import ccall "Rts.h shutdownHaskellAndExit"
shutdownHaskellAndExit :: CInt -> CInt -> IO ()
useFastExit, useSafeExit :: CInt
useFastExit :: CInt
useFastExit = CInt
1
useSafeExit :: CInt
useSafeExit = CInt
0