packages feed

stack-3.11.1: src/unix/Stack/Build/TestSuiteTimeout.hs

{-# LANGUAGE NoImplicitPrelude #-}

{-|
Module      : Stack.Build.TestSuiteTimeout
Description : OS-specific test suite timeout termination helpers.
License     : BSD-3-Clause
-}

module Stack.Build.TestSuiteTimeout
  ( prepareForEscalation
  , terminateGracefully
  , forceKill
  ) where

import           RIO.Process ( ProcessConfig, setNewSession )
import qualified RIO.Process as RP ( Process, unsafeProcessHandle )
import           Stack.Prelude
import           System.Posix.Signals
                   ( sigKILL, sigTERM, signalProcess, signalProcessGroup )
import qualified System.Process as Process

prepareForEscalation :: ProcessConfig stdin stdout stderr -> ProcessConfig stdin stdout stderr
prepareForEscalation = setNewSession True

terminateGracefully :: RP.Process stdin stdout stderr -> RIO env ()
terminateGracefully p = do
  let processHandle = RP.unsafeProcessHandle p
  mpid <- liftIO $ Process.getPid processHandle
  forM_ mpid $ \pid -> do
    -- In a new session, the initial pid is also the process group id.
    void $ tryAny $ liftIO $ signalProcessGroup sigTERM pid
    void $ tryAny $ liftIO $ signalProcess sigTERM pid

forceKill :: RP.Process stdin stdout stderr -> RIO env ()
forceKill p = do
  let processHandle = RP.unsafeProcessHandle p
  mpid <- liftIO $ Process.getPid processHandle
  forM_ mpid $ \pid -> do
    void $ tryAny $ liftIO $ signalProcessGroup sigKILL pid
    void $ tryAny $ liftIO $ signalProcess sigKILL pid