ghc-dup: 08066879b00ee7e1eca27df1128f73df88392c60

     1: {-# OPTIONS -cpp #-}
     2: module Main where
     3: 
     4: import Control.Concurrent (forkIO, threadDelay)
     5: import Control.Concurrent.MVar (putMVar, takeMVar, newEmptyMVar)
     6: import Control.Monad
     7: import Control.Exception
     8: import Data.Maybe (isNothing)
     9: import System.Environment (getArgs)
    10: import System.Exit
    11: import System.IO (hPutStrLn, stderr)
    12: 
    13: #if !defined(mingw32_HOST_OS)
    14: import System.Posix hiding (killProcess)
    15: import System.IO.Error hiding (try,catch)
    16: #endif
    17: 
    18: #if defined(mingw32_HOST_OS)
    19: import System.Process
    20: import WinCBindings
    21: import Foreign
    22: import System.Win32.DebugApi
    23: import System.Win32.Types
    24: #endif
    25: 
    26: main :: IO ()
    27: main = do
    28:   args <- getArgs
    29:   case args of
    30:       [secs,cmd] ->
    31:           case reads secs of
    32:           [(secs', "")] -> run secs' cmd
    33:           _ -> die ("Can't parse " ++ show secs ++ " as a number of seconds")
    34:       _ -> die ("Bad arguments " ++ show args)
    35: 
    36: die :: String -> IO ()
    37: die msg = do hPutStrLn stderr ("timeout: " ++ msg)
    38:              exitWith (ExitFailure 1)
    39: 
    40: timeoutMsg :: String
    41: timeoutMsg = "Timeout happened...killing process..."
    42: 
    43: run :: Int -> String -> IO ()
    44: #if !defined(mingw32_HOST_OS)
    45: run secs cmd = do
    46:         m <- newEmptyMVar
    47:         mp <- newEmptyMVar
    48:         installHandler sigINT (Catch (putMVar m Nothing)) Nothing
    49:         forkIO $ do threadDelay (secs * 1000000)
    50:                     putMVar m Nothing
    51:         forkIO $ do ei <- try $ do pid <- systemSession cmd
    52:                                    return pid
    53:                     putMVar mp ei
    54:                     case ei of
    55:                        Left _ -> return ()
    56:                        Right pid -> do
    57:                            r <- getProcessStatus True False pid
    58:                            putMVar m r
    59:         ei_pid_ph <- takeMVar mp
    60:         case ei_pid_ph of
    61:             Left e -> do hPutStrLn stderr
    62:                                    ("Timeout:\n" ++ show (e :: IOException))
    63:                          exitWith (ExitFailure 98)
    64:             Right pid -> do
    65:                 r <- takeMVar m
    66:                 case r of
    67:                   Nothing -> do
    68:                         hPutStrLn stderr timeoutMsg
    69:                         killProcess pid
    70:                         exitWith (ExitFailure 99)
    71:                   Just (Exited r) -> exitWith r
    72:                   Just (Terminated s) -> raiseSignal s
    73:                   Just _ -> exitWith (ExitFailure 1)
    74: 
    75: systemSession cmd =
    76:  forkProcess $ do
    77:    createSession
    78:    executeFile "/bin/sh" False ["-c", cmd] Nothing
    79:    -- need to use exec() directly here, rather than something like
    80:    -- System.Process.system, because we are in a forked child and some
    81:    -- pthread libraries get all upset if you start doing certain
    82:    -- things in a forked child of a pthread process, such as forking
    83:    -- more threads.
    84: 
    85: killProcess pid = do
    86:   ignoreIOExceptions (signalProcessGroup sigTERM pid)
    87:   checkReallyDead 10
    88:   where
    89:     checkReallyDead 0 = hPutStrLn stderr "checkReallyDead: Giving up"
    90:     checkReallyDead (n+1) =
    91:       do threadDelay (3*100000) -- 3/10 sec
    92:          m <- tryJust (guard . isDoesNotExistError) $
    93:                  getProcessStatus False False pid
    94:          case m of
    95:             Right Nothing -> return ()
    96:             Left _ -> return ()
    97:             _ -> do
    98:               ignoreIOExceptions (signalProcessGroup sigKILL pid)
    99:               checkReallyDead n
   100: 
   101: ignoreIOExceptions :: IO () -> IO ()
   102: ignoreIOExceptions io = io `catch` ((\_ -> return ()) :: IOException -> IO ())
   103: 
   104: #else
   105: run secs cmd =
   106:     let escape '\\' = "\\\\"
   107:         escape '"'  = "\\\""
   108:         escape c    = [c]
   109:         cmd' = "sh -c \"" ++ concatMap escape cmd ++ "\"" in
   110:     alloca $ \p_startupinfo ->
   111:     alloca $ \p_pi ->
   112:     withTString cmd' $ \cmd'' ->
   113:     do job <- createJobObjectW nullPtr nullPtr
   114:        let creationflags = 0
   115:        b <- createProcessW nullPtr cmd'' nullPtr nullPtr True
   116:                            creationflags
   117:                            nullPtr nullPtr p_startupinfo p_pi
   118:        unless b $ errorWin "createProcessW"
   119:        pi <- peek p_pi
   120:        assignProcessToJobObject job (piProcess pi)
   121:        resumeThread (piThread pi)
   122: 
   123:        -- The program is now running
   124: 
   125:        let handle = piProcess pi
   126:        let millisecs = secs * 1000
   127:        rc <- waitForSingleObject handle (fromIntegral millisecs)
   128:        if rc == cWAIT_TIMEOUT
   129:            then do hPutStrLn stderr timeoutMsg
   130:                    terminateJobObject job 99
   131:                    exitWith (ExitFailure 99)
   132:            else alloca $ \p_exitCode ->
   133:                 do r <- getExitCodeProcess handle p_exitCode
   134:                    if r then do ec <- peek p_exitCode
   135:                                 let ec' = if ec == 0
   136:                                           then ExitSuccess
   137:                                           else ExitFailure $ fromIntegral ec
   138:                                 exitWith ec'
   139:                         else errorWin "getExitCodeProcess"
   140: #endif
   141: 

Generated by git2html.