2020-04-01 22:06:00 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Functions for managing processes
|
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
module XMonad.Internal.Process
|
|
|
|
( waitUntilExit
|
2020-04-06 00:14:56 -04:00
|
|
|
, killHandle
|
|
|
|
, spawnPipe
|
|
|
|
, createProcess'
|
|
|
|
, proc'
|
|
|
|
, shell'
|
|
|
|
, spawn
|
|
|
|
, spawnAt
|
|
|
|
, module System.Process
|
2020-04-01 20:17:47 -04:00
|
|
|
) where
|
2020-03-26 09:37:46 -04:00
|
|
|
|
|
|
|
import Control.Concurrent
|
|
|
|
import Control.Exception
|
|
|
|
import Control.Monad
|
2020-07-06 21:08:32 -04:00
|
|
|
import Control.Monad.IO.Class
|
2020-03-26 09:37:46 -04:00
|
|
|
|
2020-04-11 13:46:51 -04:00
|
|
|
import Data.Maybe
|
|
|
|
|
2020-03-26 09:37:46 -04:00
|
|
|
import System.Directory
|
|
|
|
import System.Exit
|
2020-03-28 14:44:50 -04:00
|
|
|
import System.IO
|
2020-03-26 09:37:46 -04:00
|
|
|
import System.Posix.Signals
|
2020-04-06 00:14:56 -04:00
|
|
|
import System.Process
|
2020-03-26 09:37:46 -04:00
|
|
|
|
2020-07-06 21:08:32 -04:00
|
|
|
import XMonad.Core hiding (spawn)
|
2020-03-28 14:44:50 -04:00
|
|
|
|
2020-03-26 09:37:46 -04:00
|
|
|
-- | Block until a PID has exited (in any form)
|
|
|
|
-- ASSUMPTION on linux PIDs will always increase until they overflow, in which
|
|
|
|
-- case they will start to recycle. Barring any fork bombs, this code should
|
|
|
|
-- work because we can reasonably expect that no processes will spawn with the
|
|
|
|
-- same PID within the delay limit
|
|
|
|
-- TODO this will not work if the process is a zombie (maybe I care...)
|
|
|
|
waitUntilExit :: Show t => t -> IO ()
|
|
|
|
waitUntilExit pid = do
|
|
|
|
res <- doesDirectoryExist $ "/proc/" ++ show pid
|
|
|
|
when res $ threadDelay 100000 >> waitUntilExit pid
|
|
|
|
|
2020-04-06 00:14:56 -04:00
|
|
|
killHandle :: ProcessHandle -> IO ()
|
|
|
|
killHandle ph = do
|
2020-04-11 13:46:51 -04:00
|
|
|
ec <- getProcessExitCode ph
|
|
|
|
unless (isJust ec) $ do
|
|
|
|
pid <- getPid ph
|
|
|
|
forM_ pid $ signalProcess sigTERM
|
|
|
|
-- this may fail if the process exits instantly and the handle
|
|
|
|
-- is destroyed by the time we get to this line (I think?)
|
|
|
|
void (try $ waitForProcess ph :: IO (Either IOException ExitCode))
|
2020-04-06 00:14:56 -04:00
|
|
|
|
|
|
|
withDefaultSignalHandlers :: IO a -> IO a
|
|
|
|
withDefaultSignalHandlers =
|
|
|
|
bracket_ uninstallSignalHandlers installSignalHandlers
|
|
|
|
|
|
|
|
addGroupSession :: CreateProcess -> CreateProcess
|
|
|
|
addGroupSession cp = cp { create_group = True, new_session = True }
|
|
|
|
|
|
|
|
createProcess' :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
|
|
|
|
createProcess' = withDefaultSignalHandlers . createProcess
|
|
|
|
|
|
|
|
shell' :: String -> CreateProcess
|
|
|
|
shell' = addGroupSession . shell
|
|
|
|
|
|
|
|
proc' :: FilePath -> [String] -> CreateProcess
|
|
|
|
proc' cmd args = addGroupSession $ proc cmd args
|
|
|
|
|
2020-07-06 21:08:32 -04:00
|
|
|
spawn :: MonadIO m => String -> m ()
|
2020-04-06 00:14:56 -04:00
|
|
|
spawn = io . void . createProcess' . shell'
|
|
|
|
|
2020-07-06 21:08:32 -04:00
|
|
|
spawnAt :: MonadIO m => FilePath -> String -> m ()
|
2020-04-06 00:14:56 -04:00
|
|
|
spawnAt fp cmd = io $ void $ createProcess' $ (shell' cmd) { cwd = Just fp }
|
2020-03-28 14:44:50 -04:00
|
|
|
|
2020-04-06 00:14:56 -04:00
|
|
|
spawnPipe :: String -> IO (Handle, ProcessHandle)
|
|
|
|
spawnPipe cmd = do
|
|
|
|
-- ASSUME creating a pipe will always succeed in making a Just Handle
|
|
|
|
(Just h, _, _, p) <- createProcess' $ (shell cmd) { std_in = CreatePipe }
|
2020-03-28 14:44:50 -04:00
|
|
|
hSetBuffering h LineBuffering
|
2020-04-06 00:14:56 -04:00
|
|
|
return (h, p)
|