Posix Process Primitives

Haskell Libraries
Prev | Chapter 7. The `posix` package: POSIX support | Next

# 7.2. Posix Process Primitives

    forkProcess :: IO (Maybe ProcessID)

`forkProcess` calls `fork`, returning `Just pid` to the parent, where `pid` is the ProcessID of the child, and returning `Nothing` to the child.

    executeFile :: FilePath                   -- Command
                -> Bool                       -- Search PATH?
                -> [String]                   -- Arguments
                -> Maybe [(String, String)]   -- Environment
                -> IO ()

`executeFile cmd args env` calls one of the `execv*` family, depending on whether or not the current PATH is to be searched for the command, and whether or not an environment is provided to supersede the process's current environment. The basename (leading directory names suppressed) of the command is passed to `execv*` as `arg[0]`; the argument list passed to `executeFile` therefore begins with `arg[1]`.

    Search PATH?    Supersede environ?      Call
    ~~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~      ~~~~~~~
    False           False                   execv
    False           True                    execve
    True            False                   execvp
    True            True                    execvpe*

Note that `execvpe` is not provided by the POSIX standard, and must be written by hand. Care must be taken to ensure that the search path is extracted from the original environment, and not from the environment to be passed on to the new image.

NOTE: In general, sharing open files between parent and child processes is potential bug farm, and should be avoided unless you really depend on this `feature' of POSIX' `fork()` semantics. Using Haskell, there's the extra complication that arguments to `executeFile` might come from files that are read lazily (using `hGetContents`, or some such.) If this is the case, then for your own sanity, please ensure that the arguments to `executeFile` have been fully evaluated before calling `forkProcess` (followed by `executeFile`.) Consider yourself warned :-)

A successful `executeFile` overlays the current process image with a new one, so it only returns on failure.

    runProcess :: FilePath                    -- Command
               -> [String]                    -- Arguments
               -> Maybe [(String, String)]    -- Environment (Nothing -> Inherited)
               -> Maybe FilePath              -- Working directory (Nothing -> inherited)
               -> Maybe Handle                -- stdin  (Nothing -> inherited)
               -> Maybe Handle                -- stdout (Nothing -> inherited)
               -> Maybe Handle                -- stderr (Nothing -> inherited)
               -> IO ()

`runProcess` is our candidate for the high-level OS-independent primitive.

`runProcess cmd args env wd inhdl outhdl errhdl` runs cmd (searching the current `PATH`) with arguments `args`. If `env` is `Just pairs`, the command is executed with the environment specified by `pairs` of variables and values; otherwise, the command is executed with the current environment. If `wd` is `Just dir`, the command is executed with working directory `dir`; otherwise, the command is executed in the current working directory. If `{in,out,err`hdl} is `Just handle`, the command is executed with the `Fd` for `std{in,out,err`} attached to the specified `handle`; otherwise, the `Fd` for `std{in,out,err`} is left unchanged.

    getProcessStatus :: Bool              -- Block?
                     -> Bool              -- Stopped processes?
                     -> ProcessID
                     -> IO (Maybe ProcessStatus)

`getProcessStatus blk stopped pid` calls `waitpid`, returning `Just tc`, the `ProcessStatus` for process `pid` if it is available, `Nothing` otherwise. If `blk` is `False`, then `WNOHANG` is set in the options for `waitpid`, otherwise not. If `stopped` is `True`, then `WUNTRACED` is set in the options for `waitpid`, otherwise not.

    getGroupProcessStatus :: Bool         -- Block?
                          -> Bool         -- Stopped processes?
                          -> ProcessGroupID
                          -> IO (Maybe (ProcessID, ProcessStatus))

`getGroupProcessStatus blk stopped pgid` calls `waitpid`, returning `Just (pid, tc)`, the `ProcessID` and `ProcessStatus` for any process in group `pgid` if one is available, `Nothing` otherwise. If `blk` is `False`, then `WNOHANG` is set in the options for `waitpid`, otherwise not. If `stopped` is `True`, then `WUNTRACED` is set in the options for `waitpid`, otherwise not.

    getAnyProcessStatus :: Bool           -- Block?
                        -> Bool           -- Stopped processes?
                        -> IO (Maybe (ProcessID, ProcessStatus))

`getAnyProcessStatus blk stopped` calls `waitpid`, returning `Just (pid, tc)`, the `ProcessID` and `ProcessStatus` for any child process if one is available, `Nothing` otherwise. If `blk` is `False`, then `WNOHANG` is set in the options for `waitpid`, otherwise not. If `stopped` is `True`, then `WUNTRACED` is set in the options for `waitpid`, otherwise not.

    exitImmediately :: ExitCode -> IO ()

`exitImmediately status` calls `_exit` to terminate the process with the indicated exit `status`. The operation never returns.

    getEnvironment :: IO [(String, String)]

`getEnvironment` parses the environment variable mapping provided by `environ`, returning `(variable, value)` pairs. The operation never fails.

    setEnvironment :: [(String, String)] -> IO ()

`setEnvironment` replaces the process environment with the provided mapping of `(variable, value)` pairs.

    getEnvVar :: String -> IO String

`getEnvVar var` returns the value associated with variable `var` in the current environment (identical functionality provided through standard Haskell library function `System.getEnv`).

The operation may fail with:

`NoSuchThing`

  The variable has no mapping in the current environment.

    setEnvVar :: String -> String -> IO ()

`setEnvVar var val` sets the value associated with variable `var` in the current environment to be `val`. Any previous mapping is superseded.

    removeEnvVar :: String -> IO ()

`removeEnvVar var` removes any value associated with variable `var` in the current environment. Deleting a variable for which there is no mapping does not generate an error.

    nullSignal :: Signal
    nullSignal = 0

    backgroundRead, sigTTIN        :: Signal
    backgroundWrite, sigTTOU       :: Signal
    continueProcess, sigCONT       :: Signal
    floatingPointException, sigFPE :: Signal
    illegalInstruction, sigILL     :: Signal
    internalAbort, sigABRT         :: Signal
    keyboardSignal, sigINT         :: Signal
    keyboardStop, sigTSTP          :: Signal
    keyboardTermination, sigQUIT   :: Signal
    killProcess, sigKILL           :: Signal
    lostConnection, sigHUP         :: Signal
    openEndedPipe, sigPIPE         :: Signal
    processStatusChanged, sigCHLD  :: Signal
    realTimeAlarm, sigALRM         :: Signal
    segmentationViolation, sigSEGV :: Signal
    softwareStop, sigSTOP          :: Signal
    softwareTermination, sigTERM   :: Signal
    userDefinedSignal1, sigUSR1    :: Signal
    userDefinedSignal2, sigUSR2    :: Signal

    signalProcess :: Signal -> ProcessID -> IO ()

`signalProcess int pid` calls `kill` to signal process `pid` with interrupt signal `int`.

    raiseSignal :: Signal -> IO ()

`raiseSignal int` calls `kill` to signal the current process with interrupt signal `int`.

    signalProcessGroup :: Signal -> ProcessGroupID -> IO ()

`signalProcessGroup int pgid` calls `kill` to signal all processes in group `pgid` with interrupt signal `int`.

    setStoppedChildFlag :: Bool -> IO Bool

`setStoppedChildFlag bool` sets a flag which controls whether or not the `NOCLDSTOP` option will be used the next time a signal handler is installed for `SIGCHLD`. If `bool` is `True` (the default), `NOCLDSTOP` will not be used; otherwise it will be. The operation never fails.

    queryStoppedChildFlag :: IO Bool

`queryStoppedChildFlag` queries the flag which controls whether or not the `NOCLDSTOP` option will be used the next time a signal handler is installed for `SIGCHLD`. If `NOCLDSTOP` will be used, it returns `False`; otherwise (the default) it returns `True`. The operation never fails.

    emptySignalSet :: SignalSet
    fullSignalSet  :: SignalSet
    addSignal      :: Signal -> SignalSet -> SignalSet
    deleteSignal   :: Signal -> SignalSet -> SignalSet
    inSignalSet    :: Signal -> SignalSet -> Bool

    installHandler :: Signal
                   -> Handler
                   -> Maybe SignalSet       -- other signals to block
                   -> IO Handler            -- old handler

`installHandler int handler iset` calls `sigaction` to install an interrupt handler for signal `int`. If `handler` is `Default`, `SIG_DFL` is installed; if `handler` is `Ignore`, `SIG_IGN` is installed; if `handler` is `Catch action`, a handler is installed which will invoke `action` in a new thread when (or shortly after) the signal is received. See Chapter 2 for details on how to communicate between threads.

If `iset` is `Just s`, then the `sa_mask` of the `sigaction` structure is set to `s`; otherwise it is cleared. The previously installed signal handler for `int` is returned.

    getSignalMask :: IO SignalSet

`getSignalMask` calls `sigprocmask` to determine the set of interrupts which are currently being blocked.

    setSignalMask :: SignalSet -> IO SignalSet

`setSignalMask mask` calls `sigprocmask` with `SIG_SETMASK` to block all interrupts in `mask`. The previous set of blocked interrupts is returned.

    blockSignals :: SignalSet -> IO SignalSet

`setSignalMask mask` calls `sigprocmask` with `SIG_BLOCK` to add all interrupts in `mask` to the set of blocked interrupts. The previous set of blocked interrupts is returned.

    unBlockSignals :: SignalSet -> IO SignalSet

`setSignalMask mask` calls `sigprocmask` with `SIG_UNBLOCK` to remove all interrupts in `mask` from the set of blocked interrupts. The previous set of blocked interrupts is returned.

    getPendingSignals :: IO SignalSet

`getPendingSignals` calls `sigpending` to obtain the set of interrupts which have been received but are currently blocked.

    awaitSignal :: Maybe SignalSet -> IO ()

`awaitSignal iset` suspends execution until an interrupt is received. If `iset` is `Just s`, `awaitSignal` calls `sigsuspend`, installing `s` as the new signal mask before suspending execution; otherwise, it calls `pause`. `awaitSignal` returns on receipt of a signal. If you have installed any signal handlers with `installHandler`, it may be wise to call `yield` directly after `awaitSignal` to ensure that the signal handler runs as promptly.

    scheduleAlarm :: Int -> IO Int

`scheduleAlarm i` calls `alarm` to schedule a real time alarm at least `i` seconds in the future.

    sleep :: Int -> IO ()

`sleep i` calls `sleep` to suspend execution of the program until at least `i` seconds have elapsed or a signal is received.

Prev | Home | Next
The `posix` package: POSIX support | Up | Posix Process Environment