2012-05-14 11:15:50 +04:00
|
|
|
{-# LANGUAGE NoImplicitPrelude #-}
|
2012-05-06 14:28:18 +04:00
|
|
|
module Keter.Process
|
|
|
|
( run
|
|
|
|
, terminate
|
|
|
|
, Process
|
|
|
|
) where
|
|
|
|
|
2012-05-14 11:15:50 +04:00
|
|
|
import Keter.Prelude
|
2012-05-06 14:28:18 +04:00
|
|
|
import qualified System.Process as SP
|
|
|
|
|
|
|
|
data Status = NeedsRestart | NoRestart | Running SP.ProcessHandle
|
|
|
|
|
|
|
|
-- | Run the given command, restarting if the process dies.
|
|
|
|
run :: FilePath -- ^ executable
|
|
|
|
-> FilePath -- ^ working directory
|
|
|
|
-> [String] -- ^ command line parameter
|
|
|
|
-> [(String, String)] -- ^ environment
|
2012-05-14 12:03:57 +04:00
|
|
|
-> KIO Process
|
2012-05-06 14:28:18 +04:00
|
|
|
run exec dir args env = do
|
2012-05-14 12:03:57 +04:00
|
|
|
mstatus <- newMVar NeedsRestart
|
2012-05-06 14:28:18 +04:00
|
|
|
let loop = do
|
2012-05-14 12:03:57 +04:00
|
|
|
next <- modifyMVar mstatus $ \status ->
|
2012-05-06 14:28:18 +04:00
|
|
|
case status of
|
|
|
|
NoRestart -> return (NoRestart, return ())
|
|
|
|
_ -> do
|
2012-05-11 12:42:56 +04:00
|
|
|
-- FIXME put in some kind of rate limiting: if we last
|
|
|
|
-- tried to restart within five second, wait an extra
|
|
|
|
-- five seconds
|
2012-05-14 12:03:57 +04:00
|
|
|
res <- liftIO $ SP.createProcess cp
|
|
|
|
case res of
|
|
|
|
Left e -> do
|
|
|
|
log $ ExceptionThrown e
|
|
|
|
return (NeedsRestart, return ())
|
|
|
|
Right (_, _, _, ph) -> do
|
|
|
|
log $ ProcessCreated exec
|
|
|
|
return (Running ph, liftIO (SP.waitForProcess ph) >> loop)
|
2012-05-06 14:28:18 +04:00
|
|
|
next
|
2012-05-14 12:03:57 +04:00
|
|
|
forkKIO loop
|
2012-05-06 14:28:18 +04:00
|
|
|
return $ Process mstatus
|
|
|
|
where
|
2012-05-14 11:15:50 +04:00
|
|
|
cp = (SP.proc (toString exec) $ map toString args)
|
|
|
|
{ SP.cwd = Just $ toString dir
|
|
|
|
, SP.env = Just $ map (toString *** toString) env
|
2012-05-06 14:28:18 +04:00
|
|
|
, SP.std_in = SP.Inherit -- FIXME
|
|
|
|
, SP.std_out = SP.Inherit -- FIXME
|
|
|
|
, SP.std_err = SP.Inherit -- FIXME
|
|
|
|
, SP.close_fds = True
|
|
|
|
}
|
|
|
|
|
|
|
|
-- | Abstract type containing information on a process which will be restarted.
|
2012-05-14 12:03:57 +04:00
|
|
|
newtype Process = Process (MVar Status)
|
2012-05-06 14:28:18 +04:00
|
|
|
|
|
|
|
-- | Terminate the process and prevent it from being restarted.
|
2012-05-14 12:03:57 +04:00
|
|
|
terminate :: Process -> KIO ()
|
2012-05-06 14:28:18 +04:00
|
|
|
terminate (Process mstatus) = do
|
2012-05-14 12:03:57 +04:00
|
|
|
status <- swapMVar mstatus NoRestart
|
2012-05-06 14:28:18 +04:00
|
|
|
case status of
|
2012-05-14 12:03:57 +04:00
|
|
|
Running ph -> void $ liftIO $ SP.terminateProcess ph
|
2012-05-06 14:28:18 +04:00
|
|
|
_ -> return ()
|