{-# LANGUAGE CPP, ScopedTypeVariables, LambdaCase #-}
module Panic (
GhcException(..), showGhcException,
throwGhcException, throwGhcExceptionIO,
handleGhcException,
PlainPanic.progName,
pgmError,
panic, sorry, assertPanic, trace,
panicDoc, sorryDoc, pgmErrorDoc,
cmdLineError, cmdLineErrorIO,
Exception.Exception(..), showException, safeShowException,
try, tryMost, throwTo,
withSignalHandlers,
) where
import GhcPrelude
import {-# SOURCE #-} Outputable (SDoc, showSDocUnsafe)
import PlainPanic
import Exception
import Control.Monad.IO.Class
import Control.Concurrent
import Data.Typeable ( cast )
import Debug.Trace ( trace )
import System.IO.Unsafe
#if !defined(mingw32_HOST_OS)
import System.Posix.Signals as S
#endif
#if defined(mingw32_HOST_OS)
import GHC.ConsoleHandler as S
#endif
import System.Mem.Weak ( deRefWeak )
data GhcException
= Signal Int
| UsageError String
| CmdLineError String
| Panic String
| PprPanic String SDoc
| Sorry String
| PprSorry String SDoc
| InstallationError String
| ProgramError String
| PprProgramError String SDoc
instance Exception GhcException where
fromException :: SomeException -> Maybe GhcException
fromException (SomeException e :: e
e)
| Just ge :: GhcException
ge <- e -> Maybe GhcException
forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast e
e = GhcException -> Maybe GhcException
forall a. a -> Maybe a
Just GhcException
ge
| Just pge :: PlainGhcException
pge <- e -> Maybe PlainGhcException
forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast e
e = GhcException -> Maybe GhcException
forall a. a -> Maybe a
Just (GhcException -> Maybe GhcException)
-> GhcException -> Maybe GhcException
forall a b. (a -> b) -> a -> b
$
case PlainGhcException
pge of
PlainSignal n :: Int
n -> Int -> GhcException
Signal Int
n
PlainUsageError str :: String
str -> String -> GhcException
UsageError String
str
PlainCmdLineError str :: String
str -> String -> GhcException
CmdLineError String
str
PlainPanic str :: String
str -> String -> GhcException
Panic String
str
PlainSorry str :: String
str -> String -> GhcException
Sorry String
str
PlainInstallationError str :: String
str -> String -> GhcException
InstallationError String
str
PlainProgramError str :: String
str -> String -> GhcException
ProgramError String
str
| Bool
otherwise = Maybe GhcException
forall a. Maybe a
Nothing
instance Show GhcException where
showsPrec :: Int -> GhcException -> ShowS
showsPrec _ e :: GhcException
e@(ProgramError _) = GhcException -> ShowS
showGhcException GhcException
e
showsPrec _ e :: GhcException
e@(CmdLineError _) = String -> ShowS
showString "<command line>: " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GhcException -> ShowS
showGhcException GhcException
e
showsPrec _ e :: GhcException
e = String -> ShowS
showString String
progName ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString ": " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GhcException -> ShowS
showGhcException GhcException
e
showException :: Exception e => e -> String
showException :: e -> String
showException = e -> String
forall a. Show a => a -> String
show
safeShowException :: Exception e => e -> IO String
safeShowException :: e -> IO String
safeShowException e :: e
e = do
Either SomeException String
r <- IO String -> IO (Either SomeException String)
forall e a. Exception e => IO a -> IO (Either e a)
try (String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$! ShowS
forall a. [a] -> [a]
forceList (e -> String
forall e. Exception e => e -> String
showException e
e))
case Either SomeException String
r of
Right msg :: String
msg -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
msg
Left e' :: SomeException
e' -> SomeException -> IO String
forall e. Exception e => e -> IO String
safeShowException (SomeException
e' :: SomeException)
where
forceList :: [a] -> [a]
forceList [] = []
forceList xs :: [a]
xs@(x :: a
x : xt :: [a]
xt) = a
x a -> [a] -> [a]
forall a b. a -> b -> b
`seq` [a] -> [a]
forceList [a]
xt [a] -> [a] -> [a]
forall a b. a -> b -> b
`seq` [a]
xs
showGhcException :: GhcException -> ShowS
showGhcException :: GhcException -> ShowS
showGhcException = PlainGhcException -> ShowS
showPlainGhcException (PlainGhcException -> ShowS)
-> (GhcException -> PlainGhcException) -> GhcException -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
Signal n :: Int
n -> Int -> PlainGhcException
PlainSignal Int
n
UsageError str :: String
str -> String -> PlainGhcException
PlainUsageError String
str
CmdLineError str :: String
str -> String -> PlainGhcException
PlainCmdLineError String
str
Panic str :: String
str -> String -> PlainGhcException
PlainPanic String
str
Sorry str :: String
str -> String -> PlainGhcException
PlainSorry String
str
InstallationError str :: String
str -> String -> PlainGhcException
PlainInstallationError String
str
ProgramError str :: String
str -> String -> PlainGhcException
PlainProgramError String
str
PprPanic str :: String
str sdoc :: SDoc
sdoc -> String -> PlainGhcException
PlainPanic (String -> PlainGhcException) -> String -> PlainGhcException
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
str, "\n\n", SDoc -> String
showSDocUnsafe SDoc
sdoc]
PprSorry str :: String
str sdoc :: SDoc
sdoc -> String -> PlainGhcException
PlainProgramError (String -> PlainGhcException) -> String -> PlainGhcException
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
str, "\n\n", SDoc -> String
showSDocUnsafe SDoc
sdoc]
PprProgramError str :: String
str sdoc :: SDoc
sdoc -> String -> PlainGhcException
PlainProgramError (String -> PlainGhcException) -> String -> PlainGhcException
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
str, "\n\n", SDoc -> String
showSDocUnsafe SDoc
sdoc]
throwGhcException :: GhcException -> a
throwGhcException :: GhcException -> a
throwGhcException = GhcException -> a
forall a e. Exception e => e -> a
Exception.throw
throwGhcExceptionIO :: GhcException -> IO a
throwGhcExceptionIO :: GhcException -> IO a
throwGhcExceptionIO = GhcException -> IO a
forall e a. Exception e => e -> IO a
Exception.throwIO
handleGhcException :: ExceptionMonad m => (GhcException -> m a) -> m a -> m a
handleGhcException :: (GhcException -> m a) -> m a -> m a
handleGhcException = (GhcException -> m a) -> m a -> m a
forall (m :: * -> *) e a.
(ExceptionMonad m, Exception e) =>
(e -> m a) -> m a -> m a
ghandle
panicDoc, sorryDoc, pgmErrorDoc :: String -> SDoc -> a
panicDoc :: String -> SDoc -> a
panicDoc x :: String
x doc :: SDoc
doc = GhcException -> a
forall a. GhcException -> a
throwGhcException (String -> SDoc -> GhcException
PprPanic String
x SDoc
doc)
sorryDoc :: String -> SDoc -> a
sorryDoc x :: String
x doc :: SDoc
doc = GhcException -> a
forall a. GhcException -> a
throwGhcException (String -> SDoc -> GhcException
PprSorry String
x SDoc
doc)
pgmErrorDoc :: String -> SDoc -> a
pgmErrorDoc x :: String
x doc :: SDoc
doc = GhcException -> a
forall a. GhcException -> a
throwGhcException (String -> SDoc -> GhcException
PprProgramError String
x SDoc
doc)
tryMost :: IO a -> IO (Either SomeException a)
tryMost :: IO a -> IO (Either SomeException a)
tryMost action :: IO a
action = do Either SomeException a
r <- IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
try IO a
action
case Either SomeException a
r of
Left se :: SomeException
se ->
case SomeException -> Maybe GhcException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
Just (Signal _) -> SomeException -> IO (Either SomeException a)
forall e a. Exception e => e -> IO a
throwIO SomeException
se
Just (Panic _) -> SomeException -> IO (Either SomeException a)
forall e a. Exception e => e -> IO a
throwIO SomeException
se
Just _ -> Either SomeException a -> IO (Either SomeException a)
forall (m :: * -> *) a. Monad m => a -> m a
return (SomeException -> Either SomeException a
forall a b. a -> Either a b
Left SomeException
se)
Nothing ->
case SomeException -> Maybe IOException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
Just (IOException
_ :: IOException) ->
Either SomeException a -> IO (Either SomeException a)
forall (m :: * -> *) a. Monad m => a -> m a
return (SomeException -> Either SomeException a
forall a b. a -> Either a b
Left SomeException
se)
Nothing -> SomeException -> IO (Either SomeException a)
forall e a. Exception e => e -> IO a
throwIO SomeException
se
Right v :: a
v -> Either SomeException a -> IO (Either SomeException a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Either SomeException a
forall a b. b -> Either a b
Right a
v)
{-# NOINLINE signalHandlersRefCount #-}
#if !defined(mingw32_HOST_OS)
signalHandlersRefCount :: MVar (Word, Maybe (S.Handler,S.Handler
,S.Handler,S.Handler))
#else
signalHandlersRefCount :: MVar (Word, Maybe S.Handler)
#endif
signalHandlersRefCount :: MVar (Word, Maybe (Handler, Handler, Handler, Handler))
signalHandlersRefCount = IO (MVar (Word, Maybe (Handler, Handler, Handler, Handler)))
-> MVar (Word, Maybe (Handler, Handler, Handler, Handler))
forall a. IO a -> a
unsafePerformIO (IO (MVar (Word, Maybe (Handler, Handler, Handler, Handler)))
-> MVar (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO (MVar (Word, Maybe (Handler, Handler, Handler, Handler)))
-> MVar (Word, Maybe (Handler, Handler, Handler, Handler))
forall a b. (a -> b) -> a -> b
$ (Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (MVar (Word, Maybe (Handler, Handler, Handler, Handler)))
forall a. a -> IO (MVar a)
newMVar (0,Maybe (Handler, Handler, Handler, Handler)
forall a. Maybe a
Nothing)
withSignalHandlers :: (ExceptionMonad m, MonadIO m) => m a -> m a
withSignalHandlers :: m a -> m a
withSignalHandlers act :: m a
act = do
ThreadId
main_thread <- IO ThreadId -> m ThreadId
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ThreadId
myThreadId
Weak ThreadId
wtid <- IO (Weak ThreadId) -> m (Weak ThreadId)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (ThreadId -> IO (Weak ThreadId)
mkWeakThreadId ThreadId
main_thread)
let
interrupt :: IO ()
interrupt = do
Maybe ThreadId
r <- Weak ThreadId -> IO (Maybe ThreadId)
forall v. Weak v -> IO (Maybe v)
deRefWeak Weak ThreadId
wtid
case Maybe ThreadId
r of
Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just t :: ThreadId
t -> ThreadId -> AsyncException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
t AsyncException
UserInterrupt
#if !defined(mingw32_HOST_OS)
let installHandlers :: IO (Handler, Handler, Handler, Handler)
installHandlers = do
let installHandler' :: Signal -> Handler -> IO Handler
installHandler' a :: Signal
a b :: Handler
b = Signal -> Handler -> Maybe SignalSet -> IO Handler
installHandler Signal
a Handler
b Maybe SignalSet
forall a. Maybe a
Nothing
Handler
hdlQUIT <- Signal -> Handler -> IO Handler
installHandler' Signal
sigQUIT (IO () -> Handler
Catch IO ()
interrupt)
Handler
hdlINT <- Signal -> Handler -> IO Handler
installHandler' Signal
sigINT (IO () -> Handler
Catch IO ()
interrupt)
let fatal_signal :: a -> IO ()
fatal_signal n :: a
n = ThreadId -> GhcException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
main_thread (Int -> GhcException
Signal (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n))
Handler
hdlHUP <- Signal -> Handler -> IO Handler
installHandler' Signal
sigHUP (IO () -> Handler
Catch (Signal -> IO ()
forall a. Integral a => a -> IO ()
fatal_signal Signal
sigHUP))
Handler
hdlTERM <- Signal -> Handler -> IO Handler
installHandler' Signal
sigTERM (IO () -> Handler
Catch (Signal -> IO ()
forall a. Integral a => a -> IO ()
fatal_signal Signal
sigTERM))
(Handler, Handler, Handler, Handler)
-> IO (Handler, Handler, Handler, Handler)
forall (m :: * -> *) a. Monad m => a -> m a
return (Handler
hdlQUIT,Handler
hdlINT,Handler
hdlHUP,Handler
hdlTERM)
let uninstallHandlers :: (Handler, Handler, Handler, Handler) -> IO ()
uninstallHandlers (hdlQUIT :: Handler
hdlQUIT,hdlINT :: Handler
hdlINT,hdlHUP :: Handler
hdlHUP,hdlTERM :: Handler
hdlTERM) = do
Handler
_ <- Signal -> Handler -> Maybe SignalSet -> IO Handler
installHandler Signal
sigQUIT Handler
hdlQUIT Maybe SignalSet
forall a. Maybe a
Nothing
Handler
_ <- Signal -> Handler -> Maybe SignalSet -> IO Handler
installHandler Signal
sigINT Handler
hdlINT Maybe SignalSet
forall a. Maybe a
Nothing
Handler
_ <- Signal -> Handler -> Maybe SignalSet -> IO Handler
installHandler Signal
sigHUP Handler
hdlHUP Maybe SignalSet
forall a. Maybe a
Nothing
Handler
_ <- Signal -> Handler -> Maybe SignalSet -> IO Handler
installHandler Signal
sigTERM Handler
hdlTERM Maybe SignalSet
forall a. Maybe a
Nothing
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
#else
let sig_handler ControlC = interrupt
sig_handler Break = interrupt
sig_handler _ = return ()
let installHandlers = installHandler (Catch sig_handler)
let uninstallHandlers = installHandler
#endif
let mayInstallHandlers :: m ()
mayInstallHandlers = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVar (Word, Maybe (Handler, Handler, Handler, Handler))
-> ((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar (Word, Maybe (Handler, Handler, Handler, Handler))
signalHandlersRefCount (((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ())
-> ((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \case
(0,Nothing) -> do
(Handler, Handler, Handler, Handler)
hdls <- IO (Handler, Handler, Handler, Handler)
installHandlers
(Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler))
forall (m :: * -> *) a. Monad m => a -> m a
return (1,(Handler, Handler, Handler, Handler)
-> Maybe (Handler, Handler, Handler, Handler)
forall a. a -> Maybe a
Just (Handler, Handler, Handler, Handler)
hdls)
(c :: Word
c,oldHandlers :: Maybe (Handler, Handler, Handler, Handler)
oldHandlers) -> (Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler))
forall (m :: * -> *) a. Monad m => a -> m a
return (Word
cWord -> Word -> Word
forall a. Num a => a -> a -> a
+1,Maybe (Handler, Handler, Handler, Handler)
oldHandlers)
let mayUninstallHandlers :: m ()
mayUninstallHandlers = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVar (Word, Maybe (Handler, Handler, Handler, Handler))
-> ((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar (Word, Maybe (Handler, Handler, Handler, Handler))
signalHandlersRefCount (((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ())
-> ((Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler)))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \case
(1,Just hdls :: (Handler, Handler, Handler, Handler)
hdls) -> do
()
_ <- (Handler, Handler, Handler, Handler) -> IO ()
uninstallHandlers (Handler, Handler, Handler, Handler)
hdls
(Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler))
forall (m :: * -> *) a. Monad m => a -> m a
return (0,Maybe (Handler, Handler, Handler, Handler)
forall a. Maybe a
Nothing)
(c :: Word
c,oldHandlers :: Maybe (Handler, Handler, Handler, Handler)
oldHandlers) -> (Word, Maybe (Handler, Handler, Handler, Handler))
-> IO (Word, Maybe (Handler, Handler, Handler, Handler))
forall (m :: * -> *) a. Monad m => a -> m a
return (Word
cWord -> Word -> Word
forall a. Num a => a -> a -> a
-1,Maybe (Handler, Handler, Handler, Handler)
oldHandlers)
m ()
mayInstallHandlers
m a
act m a -> m () -> m a
forall (m :: * -> *) a b. ExceptionMonad m => m a -> m b -> m a
`gfinally` m ()
mayUninstallHandlers