diff options
author | tv <tv@krebsco.de> | 2019-01-26 18:39:54 +0100 |
---|---|---|
committer | tv <tv@krebsco.de> | 2019-01-26 18:39:54 +0100 |
commit | 9845ff41603b4aae961fa25d4b0093306a82d480 (patch) | |
tree | 1c5e5e56d5dc06939e2a972a3816f845b2b3462e | |
parent | 3e8aabc3993e4ad1d34c25c1caeb75ff6faa97ff (diff) |
Reaktor.Plugins.System: kill process group
-rw-r--r-- | reaktor2.cabal | 1 | ||||
-rw-r--r-- | src/Reaktor/Plugins/System.hs | 37 |
2 files changed, 29 insertions, 9 deletions
diff --git a/reaktor2.cabal b/reaktor2.cabal index 4932137..f0cff6f 100644 --- a/reaktor2.cabal +++ b/reaktor2.cabal @@ -9,6 +9,7 @@ cabal-version: >=1.10 executable reaktor build-depends: aeson, + async, attoparsec, base, blessings, diff --git a/src/Reaktor/Plugins/System.hs b/src/Reaktor/Plugins/System.hs index c23b4f0..573d11d 100644 --- a/src/Reaktor/Plugins/System.hs +++ b/src/Reaktor/Plugins/System.hs @@ -7,7 +7,8 @@ module Reaktor.Plugins.System (new) where import Blessings import Control.Applicative -import Control.Concurrent (forkIO) +import Control.Concurrent (forkIO,threadDelay) +import Control.Concurrent.Async (race) import Control.Exception import qualified Data.HashMap.Lazy as M import qualified Data.List as L @@ -22,8 +23,11 @@ import System.Exit import System.FilePath.Posix (takeBaseName) import System.IO (BufferMode(LineBuffering),hSetBuffering) import System.IO (Handle,hClose,hPutStr,hIsEOF) +import System.IO.Error (catchIOError,isDoesNotExistError) import System.Process -import System.Timeout +import System.Posix.Process (getProcessGroupIDOf) +import System.Posix.Signals (Signal,signalProcessGroup,killProcess) +import System.Posix.Types (ProcessGroupID) import qualified Text.Regex.PCRE.Heavy as RE import qualified Text.Regex.PCRE.Light as RE @@ -183,15 +187,27 @@ fork :: FilePath -> Callbacks -> IO () fork path args cwd env input hTimeout Callbacks{..} = - forkIO (withTimeout f `catch` onExcept) >> return () + forkIO (f `catch` onExcept) >> return () where f = withCreateProcess p $ \(Just inh) (Just outh) (Just errh) ph -> do + Just pid <- getPid ph + pgid <- getProcessGroupIDOf pid + mapM_ forkIO [ hPutStr inh input `finally` hClose inh, hWithLines outh onOutLine, hWithLines errh onErrLine ] - waitForProcess ph >>= onExit + + case hTimeout of + Just time -> + race (threadDelay time) (waitForProcess ph) >>= \case + Left () -> onExcept (SomeException (ErrorCall "timeout")) + Right code -> onExit code + Nothing -> + waitForProcess ph >>= onExit + + killProcessGroup pgid p = (proc path args) { cwd = cwd @@ -204,12 +220,15 @@ fork path args cwd env input hTimeout Callbacks{..} = , new_session = True } - timeoutError = errorWithoutStackTrace "timeout" - withTimeout = - case hTimeout of - Just time -> (maybe timeoutError return =<<) . timeout time - Nothing -> id +killProcessGroup :: ProcessGroupID -> IO () +killProcessGroup = signalProcessGroup' killProcess + +signalProcessGroup' :: Signal -> ProcessGroupID -> IO () +signalProcessGroup' sig pgid = + catchIOError + (signalProcessGroup sig pgid) + (\e -> if isDoesNotExistError e then return () else ioError e) hWithLines :: Handle -> (Text -> IO ()) -> IO () |