{-# LANGUAGE BangPatterns #-}{-# LANGUAGE CPP #-} #include <ghcplatform.h> moduleSystem.Process.Posix(mkProcessHandle ,translateInternal ,createProcess_Internal ,withCEnvironment ,closePHANDLE ,startDelegateControlC ,endDelegateControlC ,stopDelegateControlC ,isDefaultSignal ,ignoreSignal ,defaultSignal ,c_execvpe,pPrPr_disableITimers,createPipeInternal ,createPipeInternalFd ,interruptProcessGroupOfInternal ,runInteractiveProcess_lock )whereimportControl.ConcurrentimportControl.ExceptionimportData.BitsimportForeign.CimportForeign.MarshalimportForeign.PtrimportForeign.StorableimportSystem.IO.UnsafeimportControl.MonadimportData.CharimportSystem.IOimportSystem.Posix.Process.Internals(pPrPr_disableITimers,c_execvpe)importSystem.Posix.TypesimportSystem.Posix.InternalsimportGHC.IO.ExceptionimportSystem.Posix.SignalsasSigimportqualifiedSystem.Posix.IOasPosiximportSystem.Posix.Process(getProcessGroupIDOf)importSystem.Process.Common hiding(mb_delegate_ctlc ) #if defined(wasm32_HOST_ARCH) importSystem.IO.Error #endif #include "HsProcessConfig.h" #include "processFlags.h" mkProcessHandle ::PHANDLE ->Bool->IOProcessHandle mkProcessHandle :: PHANDLE -> Bool -> IO ProcessHandle mkProcessHandle PHANDLE p Bool mb_delegate_ctlc =doMVar ProcessHandle__ m <-ProcessHandle__ -> IO (MVar ProcessHandle__) forall a. a -> IO (MVar a) newMVar(PHANDLE -> ProcessHandle__ OpenHandle PHANDLE p )MVar () l <-() -> IO (MVar ()) forall a. a -> IO (MVar a) newMVar()ProcessHandle -> IO ProcessHandle forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return(MVar ProcessHandle__ -> Bool -> MVar () -> ProcessHandle ProcessHandle MVar ProcessHandle__ m Bool mb_delegate_ctlc MVar () l )closePHANDLE ::PHANDLE ->IO()closePHANDLE :: PHANDLE -> IO () closePHANDLE PHANDLE _=() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return()-- ------------------------------------------------------------------------------ commandToProcess{- | Turns a shell command into a raw command. Usually this involves wrapping it in an invocation of the shell. There's a difference in the signature of commandToProcess between the Windows and Unix versions. On Unix, exec takes a list of strings, and we want to pass our command to /bin/sh as a single argument. On Windows, CreateProcess takes a single string for the command, which is later decomposed by cmd.exe. In this case, we just want to prepend @\"c:\WINDOWS\CMD.EXE \/c\"@ to our command line. The command-line translation that we normally do for arguments on Windows isn't required (or desirable) here. -}commandToProcess ::CmdSpec ->(FilePath,[String])commandToProcess :: CmdSpec -> (FilePath, [FilePath]) commandToProcess (ShellCommand FilePath string )=(FilePath "/bin/sh",[FilePath "-c",FilePath string ])commandToProcess (RawCommand FilePath cmd [FilePath] args )=(FilePath cmd ,[FilePath] args )translateInternal ::String->StringtranslateInternal :: FilePath -> FilePath translateInternal FilePath ""=FilePath "''"translateInternal FilePath str -- goodChar is a pessimistic predicate, such that if an argument is-- non-empty and only contains goodChars, then there is no need to-- do any quoting or escaping|(Char -> Bool) -> FilePath -> Bool forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool allChar -> Bool goodChar FilePath str =FilePath str |Bool otherwise=Char '\''Char -> FilePath -> FilePath forall a. a -> [a] -> [a] :(Char -> FilePath -> FilePath) -> FilePath -> FilePath -> FilePath forall a b. (a -> b -> b) -> b -> [a] -> b forall (t :: * -> *) a b. Foldable t => (a -> b -> b) -> b -> t a -> b foldrChar -> FilePath -> FilePath escape FilePath "'"FilePath str whereescape :: Char -> FilePath -> FilePath escape Char '\''=FilePath -> FilePath -> FilePath showStringFilePath "'\\''"escape Char c =Char -> FilePath -> FilePath showCharChar c goodChar :: Char -> Bool goodChar Char c =Char -> Bool isAlphaNumChar c Bool -> Bool -> Bool ||Char c Char -> FilePath -> Bool forall a. Eq a => a -> [a] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `elem`FilePath "-_.,/"-- ------------------------------------------------------------------------------ UtilswithCEnvironment ::[(String,String)]->(PtrCString->IOa )->IOa withCEnvironment :: forall a. [(FilePath, FilePath)] -> (Ptr CString -> IO a) -> IO a withCEnvironment [(FilePath, FilePath)] envir Ptr CString -> IO a act =letenv' :: [FilePath] env' =((FilePath, FilePath) -> FilePath) -> [(FilePath, FilePath)] -> [FilePath] forall a b. (a -> b) -> [a] -> [b] map(\(FilePath name ,FilePath val )->FilePath name FilePath -> FilePath -> FilePath forall a. [a] -> [a] -> [a] ++(Char '='Char -> FilePath -> FilePath forall a. a -> [a] -> [a] :FilePath val ))[(FilePath, FilePath)] envir in(FilePath -> (CString -> IO a) -> IO a) -> [FilePath] -> ([CString] -> IO a) -> IO a forall a b res. (a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res withManyFilePath -> (CString -> IO a) -> IO a forall a. FilePath -> (CString -> IO a) -> IO a withFilePath[FilePath] env' (\[CString] pEnv ->CString -> [CString] -> (Ptr CString -> IO a) -> IO a forall a b. Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b withArray0CString forall a. Ptr a nullPtr[CString] pEnv Ptr CString -> IO a act )-- ------------------------------------------------------------------------------- POSIX runProcess with signal handling in the childcreateProcess_Internal ::String->CreateProcess ->IOProcRetHandles createProcess_Internal :: FilePath -> CreateProcess -> IO ProcRetHandles createProcess_Internal FilePath fun CreateProcess {cmdspec :: CreateProcess -> CmdSpec cmdspec =CmdSpec cmdsp ,cwd :: CreateProcess -> Maybe FilePath cwd =Maybe FilePath mb_cwd ,env :: CreateProcess -> Maybe [(FilePath, FilePath)] env =Maybe [(FilePath, FilePath)] mb_env ,std_in :: CreateProcess -> StdStream std_in =StdStream mb_stdin ,std_out :: CreateProcess -> StdStream std_out =StdStream mb_stdout ,std_err :: CreateProcess -> StdStream std_err =StdStream mb_stderr ,close_fds :: CreateProcess -> Bool close_fds =Bool mb_close_fds ,create_group :: CreateProcess -> Bool create_group =Bool mb_create_group ,delegate_ctlc :: CreateProcess -> Bool delegate_ctlc =Bool mb_delegate_ctlc ,detach_console :: CreateProcess -> Bool detach_console =Bool mb_detach_console ,create_new_console :: CreateProcess -> Bool create_new_console =Bool mb_create_new_console ,new_session :: CreateProcess -> Bool new_session =Bool mb_new_session ,child_group :: CreateProcess -> Maybe GroupID child_group =Maybe GroupID mb_child_group ,child_user :: CreateProcess -> Maybe UserID child_user =Maybe UserID mb_child_user }=dolet(FilePath cmd ,[FilePath] args )=CmdSpec -> (FilePath, [FilePath]) commandToProcess CmdSpec cmdsp FilePath -> IO ProcRetHandles -> IO ProcRetHandles forall a. FilePath -> IO a -> IO a withFilePathException FilePath cmd (IO ProcRetHandles -> IO ProcRetHandles) -> IO ProcRetHandles -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $(Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => (Ptr a -> IO b) -> IO b alloca((Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr FD pfdStdInput ->(Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => (Ptr a -> IO b) -> IO b alloca((Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr FD pfdStdOutput ->(Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => (Ptr a -> IO b) -> IO b alloca((Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr FD -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr FD pfdStdError ->(Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => (Ptr a -> IO b) -> IO b alloca((Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr CString pFailedDoing ->([(FilePath, FilePath)] -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> Maybe [(FilePath, FilePath)] -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b c. (a -> (Ptr b -> IO c) -> IO c) -> Maybe a -> (Ptr b -> IO c) -> IO c maybeWith[(FilePath, FilePath)] -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a. [(FilePath, FilePath)] -> (Ptr CString -> IO a) -> IO a withCEnvironment Maybe [(FilePath, FilePath)] mb_env ((Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr CString pEnv ->(FilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> Maybe FilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b c. (a -> (Ptr b -> IO c) -> IO c) -> Maybe a -> (Ptr b -> IO c) -> IO c maybeWithFilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a. FilePath -> (CString -> IO a) -> IO a withFilePathMaybe FilePath mb_cwd ((CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\CString pWorkDir ->(GroupID -> (Ptr GroupID -> IO ProcRetHandles) -> IO ProcRetHandles) -> Maybe GroupID -> (Ptr GroupID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b c. (a -> (Ptr b -> IO c) -> IO c) -> Maybe a -> (Ptr b -> IO c) -> IO c maybeWithGroupID -> (Ptr GroupID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b withMaybe GroupID mb_child_group ((Ptr GroupID -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr GroupID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr GroupID pChildGroup ->(UserID -> (Ptr UserID -> IO ProcRetHandles) -> IO ProcRetHandles) -> Maybe UserID -> (Ptr UserID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b c. (a -> (Ptr b -> IO c) -> IO c) -> Maybe a -> (Ptr b -> IO c) -> IO c maybeWithUserID -> (Ptr UserID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b withMaybe UserID mb_child_user ((Ptr UserID -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr UserID -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr UserID pChildUser ->FilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a. FilePath -> (CString -> IO a) -> IO a withFilePathFilePath cmd ((CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\CString cmdstr ->(FilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> [FilePath] -> ([CString] -> IO ProcRetHandles) -> IO ProcRetHandles forall a b res. (a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res withManyFilePath -> (CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a. FilePath -> (CString -> IO a) -> IO a withCString[FilePath] args (([CString] -> IO ProcRetHandles) -> IO ProcRetHandles) -> ([CString] -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\[CString] argstrs ->doletcstrs :: [CString] cstrs =CString cmdstr CString -> [CString] -> [CString] forall a. a -> [a] -> [a] :[CString] argstrs CString -> [CString] -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b withArray0CString forall a. Ptr a nullPtr[CString] cstrs ((Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles) -> (Ptr CString -> IO ProcRetHandles) -> IO ProcRetHandles forall a b. (a -> b) -> a -> b $\Ptr CString pargs ->doFD fdin <-FilePath -> FD -> StdStream -> IO FD mbFd FilePath fun FD fd_stdin StdStream mb_stdin FD fdout <-FilePath -> FD -> StdStream -> IO FD mbFd FilePath fun FD fd_stdout StdStream mb_stdout FD fderr <-FilePath -> FD -> StdStream -> IO FD mbFd FilePath fun FD fd_stderr StdStream mb_stderr Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () whenBool mb_delegate_ctlc IO () startDelegateControlC letflags :: FD flags =(ifBool mb_close_fds thenRUN_PROCESS_IN_CLOSE_FDSelse0)FD -> FD -> FD forall a. Bits a => a -> a -> a .|.(ifBool mb_create_group thenRUN_PROCESS_IN_NEW_GROUPelse0)FD -> FD -> FD forall a. Bits a => a -> a -> a .|.(ifBool mb_detach_console thenRUN_PROCESS_DETACHEDelse0)FD -> FD -> FD forall a. Bits a => a -> a -> a .|.(ifBool mb_create_new_console thenRUN_PROCESS_NEW_CONSOLEelse0)FD -> FD -> FD forall a. Bits a => a -> a -> a .|.(ifBool mb_new_session thenRUN_PROCESS_NEW_SESSIONelse0)FD -> FD -> FD forall a. Bits a => a -> a -> a .|.(ifBool mb_delegate_ctlc thenRESET_INT_QUIT_HANDLERSelse0)-- See the comment on runInteractiveProcess_lockPHANDLE proc_handle <-MVar () -> (() -> IO PHANDLE) -> IO PHANDLE forall a b. MVar a -> (a -> IO b) -> IO b withMVarMVar () runInteractiveProcess_lock ((() -> IO PHANDLE) -> IO PHANDLE) -> (() -> IO PHANDLE) -> IO PHANDLE forall a b. (a -> b) -> a -> b $\() _->Ptr CString -> CString -> Ptr CString -> FD -> FD -> FD -> Ptr FD -> Ptr FD -> Ptr FD -> Ptr GroupID -> Ptr UserID -> FD -> Ptr CString -> IO PHANDLE c_runInteractiveProcess Ptr CString pargs CString pWorkDir Ptr CString pEnv FD fdin FD fdout FD fderr Ptr FD pfdStdInput Ptr FD pfdStdOutput Ptr FD pfdStdError Ptr GroupID pChildGroup Ptr UserID pChildUser FD flags Ptr CString pFailedDoing Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () when(PHANDLE proc_handle PHANDLE -> PHANDLE -> Bool forall a. Eq a => a -> a -> Bool ==-PHANDLE 1)(IO () -> IO ()) -> IO () -> IO () forall a b. (a -> b) -> a -> b $doCString cFailedDoing <-Ptr CString -> IO CString forall a. Storable a => Ptr a -> IO a peekPtr CString pFailedDoing FilePath failedDoing <-CString -> IO FilePath peekCStringCString cFailedDoing Bool -> IO () -> IO () forall (f :: * -> *). Applicative f => Bool -> f () -> f () whenBool mb_delegate_ctlc IO () stopDelegateControlC FilePath -> IO () forall a. FilePath -> IO a throwErrno(FilePath fun FilePath -> FilePath -> FilePath forall a. [a] -> [a] -> [a] ++FilePath ": "FilePath -> FilePath -> FilePath forall a. [a] -> [a] -> [a] ++FilePath failedDoing )Maybe Handle hndStdInput <-StdStream -> Ptr FD -> IOMode -> IO (Maybe Handle) mbPipe StdStream mb_stdin Ptr FD pfdStdInput IOMode WriteModeMaybe Handle hndStdOutput <-StdStream -> Ptr FD -> IOMode -> IO (Maybe Handle) mbPipe StdStream mb_stdout Ptr FD pfdStdOutput IOMode ReadModeMaybe Handle hndStdError <-StdStream -> Ptr FD -> IOMode -> IO (Maybe Handle) mbPipe StdStream mb_stderr Ptr FD pfdStdError IOMode ReadModeProcessHandle ph <-PHANDLE -> Bool -> IO ProcessHandle mkProcessHandle PHANDLE proc_handle Bool mb_delegate_ctlc ProcRetHandles -> IO ProcRetHandles forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a returnProcRetHandles {hStdInput :: Maybe Handle hStdInput =Maybe Handle hndStdInput ,hStdOutput :: Maybe Handle hStdOutput =Maybe Handle hndStdOutput ,hStdError :: Maybe Handle hStdError =Maybe Handle hndStdError ,procHandle :: ProcessHandle procHandle =ProcessHandle ph }{-# NOINLINErunInteractiveProcess_lock #-}-- | 'runInteractiveProcess' blocks signals around the fork().-- Since blocking/unblocking of signals is a global state operation, we need to-- ensure mutual exclusion of calls to 'runInteractiveProcess'.-- This lock is exported so that other libraries which also need to fork()-- (and also need to make the same global state changes) can protect their changes-- with the same lock.-- See https://github.com/haskell/process/pull/154.---- @since 1.6.6.0runInteractiveProcess_lock ::MVar()runInteractiveProcess_lock :: MVar () runInteractiveProcess_lock =IO (MVar ()) -> MVar () forall a. IO a -> a unsafePerformIO(IO (MVar ()) -> MVar ()) -> IO (MVar ()) -> MVar () forall a b. (a -> b) -> a -> b $() -> IO (MVar ()) forall a. a -> IO (MVar a) newMVar()-- ------------------------------------------------------------------------------ Delegated control-C handling on Unix-- See ticket https://ghc.haskell.org/trac/ghc/ticket/2301-- and http://www.cons.org/cracauer/sigint.html---- While running an interactive console process like ghci or a shell, we want-- to let that process handle Ctl-C keyboard interrupts how it sees fit.-- So that means we need to ignore the SIGINT/SIGQUIT Unix signals while we're-- running such programs. And then if/when they do terminate, we need to check-- if they terminated due to SIGINT/SIGQUIT and if so then we behave as if we-- got the Ctl-C then, by throwing the UserInterrupt exception.---- If we run multiple programs like this concurrently then we have to be-- careful to avoid messing up the signal handlers. We keep a count and only-- restore when the last one has finished.{-# NOINLINErunInteractiveProcess_delegate_ctlc #-}runInteractiveProcess_delegate_ctlc ::MVar(Maybe(Int,Sig.Handler,Sig.Handler))runInteractiveProcess_delegate_ctlc :: MVar (Maybe (Int, Handler, Handler)) runInteractiveProcess_delegate_ctlc =IO (MVar (Maybe (Int, Handler, Handler))) -> MVar (Maybe (Int, Handler, Handler)) forall a. IO a -> a unsafePerformIO(IO (MVar (Maybe (Int, Handler, Handler))) -> MVar (Maybe (Int, Handler, Handler))) -> IO (MVar (Maybe (Int, Handler, Handler))) -> MVar (Maybe (Int, Handler, Handler)) forall a b. (a -> b) -> a -> b $Maybe (Int, Handler, Handler) -> IO (MVar (Maybe (Int, Handler, Handler))) forall a. a -> IO (MVar a) newMVarMaybe (Int, Handler, Handler) forall a. Maybe a NothingstartDelegateControlC ::IO()startDelegateControlC :: IO () startDelegateControlC =MVar (Maybe (Int, Handler, Handler)) -> (Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_MVar (Maybe (Int, Handler, Handler)) runInteractiveProcess_delegate_ctlc ((Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO ()) -> (Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO () forall a b. (a -> b) -> a -> b $\Maybe (Int, Handler, Handler) delegating ->docaseMaybe (Int, Handler, Handler) delegating ofMaybe (Int, Handler, Handler) Nothing->do-- We're going to ignore ^C in the parent while there are any-- processes using ^C delegation.---- If another thread runs another process without using-- delegation while we're doing this then it will inherit the-- ignore ^C status.Handler old_int <-FD -> Handler -> Maybe SignalSet -> IO Handler installHandlerFD sigINTHandler IgnoreMaybe SignalSet forall a. Maybe a NothingHandler old_quit <-FD -> Handler -> Maybe SignalSet -> IO Handler installHandlerFD sigQUITHandler IgnoreMaybe SignalSet forall a. Maybe a NothingMaybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler)) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return((Int, Handler, Handler) -> Maybe (Int, Handler, Handler) forall a. a -> Maybe a Just(Int 1,Handler old_int ,Handler old_quit ))Just(Int count ,Handler old_int ,Handler old_quit )->do-- If we're already doing it, just increment the countlet!count' :: Int count' =Int count Int -> Int -> Int forall a. Num a => a -> a -> a +Int 1Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler)) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return((Int, Handler, Handler) -> Maybe (Int, Handler, Handler) forall a. a -> Maybe a Just(Int count' ,Handler old_int ,Handler old_quit ))stopDelegateControlC ::IO()stopDelegateControlC :: IO () stopDelegateControlC =MVar (Maybe (Int, Handler, Handler)) -> (Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO () forall a. MVar a -> (a -> IO a) -> IO () modifyMVar_MVar (Maybe (Int, Handler, Handler)) runInteractiveProcess_delegate_ctlc ((Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO ()) -> (Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler))) -> IO () forall a b. (a -> b) -> a -> b $\Maybe (Int, Handler, Handler) delegating ->docaseMaybe (Int, Handler, Handler) delegating ofJust(Int 1,Handler old_int ,Handler old_quit )->do-- Last process, so restore the old signal handlersHandler _<-FD -> Handler -> Maybe SignalSet -> IO Handler installHandlerFD sigINTHandler old_int Maybe SignalSet forall a. Maybe a NothingHandler _<-FD -> Handler -> Maybe SignalSet -> IO Handler installHandlerFD sigQUITHandler old_quit Maybe SignalSet forall a. Maybe a NothingMaybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler)) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a returnMaybe (Int, Handler, Handler) forall a. Maybe a NothingJust(Int count ,Handler old_int ,Handler old_quit )->do-- Not the last, just decrement the countlet!count' :: Int count' =Int count Int -> Int -> Int forall a. Num a => a -> a -> a -Int 1Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler)) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return((Int, Handler, Handler) -> Maybe (Int, Handler, Handler) forall a. a -> Maybe a Just(Int count' ,Handler old_int ,Handler old_quit ))Maybe (Int, Handler, Handler) Nothing->Maybe (Int, Handler, Handler) -> IO (Maybe (Int, Handler, Handler)) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a returnMaybe (Int, Handler, Handler) forall a. Maybe a Nothing-- should be impossibleendDelegateControlC ::ExitCode->IO()endDelegateControlC :: ExitCode -> IO () endDelegateControlC ExitCode exitCode =doIO () stopDelegateControlC -- And if the process did die due to SIGINT or SIGQUIT then-- we throw our equivalent exception here (synchronously).---- An alternative design would be to throw to the main thread, as the-- normal signal handler does. But since we can be sync here, we do so.-- It allows the code locally to catch it and do something.caseExitCode exitCode ofExitFailureInt n |Int -> Bool forall {p}. Integral p => p -> Bool isSigIntQuit Int n ->AsyncException -> IO () forall e a. Exception e => e -> IO a throwIOAsyncException UserInterruptExitCode _->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return()whereisSigIntQuit :: p -> Bool isSigIntQuit p n =FD sig FD -> FD -> Bool forall a. Eq a => a -> a -> Bool ==FD sigINTBool -> Bool -> Bool ||FD sig FD -> FD -> Bool forall a. Eq a => a -> a -> Bool ==FD sigQUITwheresig :: FD sig =p -> FD forall a b. (Integral a, Num b) => a -> b fromIntegral(-p n ) #if defined(wasm32_HOST_ARCH) c_runInteractiveProcess::PtrCString->CString->PtrCString->FD->FD->FD->PtrFD->PtrFD->PtrFD->PtrCGid->PtrCUid->CInt-- flags->PtrCString->IOPHANDLEc_runInteractiveProcess_____________=ioError(ioeSetLocationunsupportedOperation"runInteractiveProcess") #else foreignimportccallunsafe"runInteractiveProcess"c_runInteractiveProcess ::PtrCString->CString->PtrCString->FD->FD->FD->PtrFD->PtrFD->PtrFD->PtrCGid->PtrCUid->CInt-- flags->PtrCString->IOPHANDLE #endif ignoreSignal ,defaultSignal ::CLongignoreSignal :: CLong ignoreSignal =CONST_SIG_IGNdefaultSignal :: CLong defaultSignal =CONST_SIG_DFLisDefaultSignal ::CLong->BoolisDefaultSignal :: CLong -> Bool isDefaultSignal =(CLong -> CLong -> Bool forall a. Eq a => a -> a -> Bool ==CLong defaultSignal )createPipeInternal ::IO(Handle,Handle)createPipeInternal :: IO (Handle, Handle) createPipeInternal =do(Fd readfd ,Fd writefd )<-IO (Fd, Fd) Posix.createPipeHandle readh <-Fd -> IO Handle Posix.fdToHandleFd readfd Handle writeh <-Fd -> IO Handle Posix.fdToHandleFd writefd (Handle, Handle) -> IO (Handle, Handle) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return(Handle readh ,Handle writeh )createPipeInternalFd ::IO(FD,FD)createPipeInternalFd :: IO (FD, FD) createPipeInternalFd =do(FdFD readfd ,FdFD writefd )<-IO (Fd, Fd) Posix.createPipe(FD, FD) -> IO (FD, FD) forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return(FD readfd ,FD writefd )interruptProcessGroupOfInternal ::ProcessHandle -- ^ A process in the process group->IO()interruptProcessGroupOfInternal :: ProcessHandle -> IO () interruptProcessGroupOfInternal ProcessHandle ph =doProcessHandle -> (ProcessHandle__ -> IO ()) -> IO () forall a. ProcessHandle -> (ProcessHandle__ -> IO a) -> IO a withProcessHandle ProcessHandle ph ((ProcessHandle__ -> IO ()) -> IO ()) -> (ProcessHandle__ -> IO ()) -> IO () forall a b. (a -> b) -> a -> b $\ProcessHandle__ p_ ->docaseProcessHandle__ p_ ofOpenExtHandle {}->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return()ClosedHandle ExitCode _->() -> IO () forall a. a -> IO a forall (m :: * -> *) a. Monad m => a -> m a return()OpenHandle PHANDLE h ->doPHANDLE pgid <-PHANDLE -> IO PHANDLE getProcessGroupIDOfPHANDLE h FD -> PHANDLE -> IO () signalProcessGroupFD sigINTPHANDLE pgid