diff options
| -rw-r--r-- | src/Main.hs | 7 | ||||
| -rw-r--r-- | src/Signal.hs | 57 | 
2 files changed, 61 insertions, 3 deletions
| diff --git a/src/Main.hs b/src/Main.hs index 9a3a2e8..64a4ea4 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -38,18 +38,18 @@ import System.Exit  import System.Environment  import System.FilePath ((</>))  import System.Posix.Files -import Control.Exception  import Control.Concurrent.Async (Async, cancel) +import Control.Exception (bracket)  import Control.Monad (unless)  import Text.Read (readMaybe) -import Signal (setupSignalHandler) +import Signal (setupSignalHandler, withDeferSignals)  -- $main  -- | The main entry point  main :: IO () -main = do +main = withDeferSignals $ do    initThreads    d <- openDisplay ""    args <- getArgs @@ -77,6 +77,7 @@ main = do  cleanupThreads :: [[([Async ()], a)]] -> IO ()  cleanupThreads vars = +  -- putStrLn "In cleanupThreads"    for_ (concat vars) $ \(asyncs, _) ->      for_ asyncs cancel diff --git a/src/Signal.hs b/src/Signal.hs index 27db46b..0948896 100644 --- a/src/Signal.hs +++ b/src/Signal.hs @@ -18,12 +18,15 @@  module Signal where +import Data.Foldable (for_)  import Data.Typeable (Typeable) +import Control.Concurrent  import Control.Concurrent.STM  import Control.Exception  import System.Posix.Signals  import Graphics.X11.Types (Button)  import Graphics.X11.Xlib.Types (Position) +import System.IO  #ifdef DBUS  import DBus (IsVariant(..)) @@ -71,3 +74,57 @@ changeScreenHandler :: TMVar SignalType -> IO ()  changeScreenHandler sig = do     atomically $ putTMVar sig ChangeScreen     return () + + +-- | Ensures that the given IO action runs its cleanup actions ('bracket' etc.), +-- even if a signal is caught. +-- +-- An exception will be thrown on the thread that called this function when a +-- signal is caught. +withDeferSignals :: IO a -> IO a +withDeferSignals thing = do +  threadId <- myThreadId +  caughtSignal <- newEmptyMVar + +  let signals = +        filter (not . flip inSignalSet reservedSignals) +          [ sigHUP +          -- , sigINT -- Handler already installed by GHC +          , sigQUIT +          , sigILL +          , sigABRT +          , sigFPE +          , sigSEGV +          --, sigPIPE -- Handler already installed by GHC +          , sigALRM +          , sigTERM +          , sigBUS +          , sigPOLL +          , sigPROF +          , sigSYS +          , sigTRAP +          , sigVTALRM +          , sigXCPU +          , sigXFSZ +          -- , sigUSR1 -- Handled by setupSignalHandler +          -- , sigUSR2 -- Handled by setupSignalHandler +          ] + +  for_ signals $ \s -> + +      installHandler s +        (Catch $ do +          tryPutMVar caughtSignal s +          hPutStrLn stderr ("xmobar: Caught signal "++show s++"; exiting...") +          throwTo threadId ThreadKilled) +        Nothing + +  thing `finally` do +        s0 <- tryReadMVar caughtSignal +        case s0 of +          Nothing -> pure () +          Just s -> do +            -- Run the default handler for the signal +            -- hPutStrLn stderr ("xmobar: Running default handler for signal "++show s) +            installHandler s Default Nothing +            raiseSignal s | 
