{-# LANGUAGE CPP #-}
module IdeSession.Util.PortableProcess where

import System.Process (ProcessHandle)

#ifdef VERSION_unix
import System.Posix.Signals
import System.Posix.Types
import System.Process.Internals (withProcessHandle, ProcessHandle__(..))
#else
import System.Process
import System.Process.Internals hiding (ProcessHandle)
import System.Win32 hiding (ProcessHandle)
#endif

#ifdef VERSION_unix
type Pid = ProcessID
#else
type Pid = ProcessId
#endif

-- Attempts to kill the process, on Unix using sigKILL
sigKillProcess :: Pid -> IO ()

-- Attempts to terminate the process, on Unix using sigTERM
sigTermProcess :: Pid -> IO ()

-- Raises a sigKILL
raiseSigKill :: IO ()

-- The exit code for sigKILL
sigKillExitCode :: Int

-- If available sends a sigKill to the given process handle
killProcessHandle :: ProcessHandle -> IO ()


#ifdef VERSION_unix
sigKillProcess = signalProcess sigKILL
sigTermProcess = signalProcess sigTERM
raiseSigKill = raiseSignal sigKILL
sigKillExitCode = -9

killProcessHandle ph = withProcessHandle ph $ \p_ ->
    case p_ of
      ClosedHandle _ ->
        leaveHandleAsIs p_
      OpenHandle pID -> do
        signalProcess sigKILL pID
        leaveHandleAsIs p_
  where
      leaveHandleAsIs _p =
#if MIN_VERSION_process(1,2,0)
        return ()
#else
        return (_p, ())
#endif

#else
-- On Windows, we just terminate, no special support for sigKILL
sigKillProcess = sigTermProcess
sigTermProcess pid = do
  ptr <- openProcess pROCESS_TERMINATE False pid
  ph <- mkProcessHandle ptr
  terminateProcess ph

sigKillExitCode = 1

-- On Windows, no special support for sigKill
killProcessHandle = terminateProcess

foreign import ccall unsafe "winbase.h GetCurrentProcessId"
    c_GetCurrentProcessId :: IO DWORD

getCurrentPid :: IO Pid
getCurrentPid = c_GetCurrentProcessId

raiseSigKill = do
  pid <- getCurrentPid
  sigKillProcess pid
#endif