Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

sys::process

The sys::process module starts and manages local child processes. A stdio handle configured as Pipe is a sys::process::Pipe, which implements the sys::io traits.

use sys::io::{Read, Lines, Write, Close};

/// An opaque handle to a managed child process.
type Proc;

/// One end of a pipe to a child process: the child's stdin (which the
/// parent writes) or its stdout or stderr (which the parent reads).
type Pipe;

impl Read for Pipe;
impl Lines for Pipe;
impl Write for Pipe;
impl Close for Pipe;

/// Where one of the child's standard streams goes.
type Redirect = [
  `Pipe,
  `Inherit,
  `Null,
];

type StdioConfig = {
  stdin: Redirect,
  stdout: Redirect,
  stderr: Redirect,
};

type SpawnOptions = {
  command: string,
  args: Array<string>,
  cwd: [string, null],
  clear_env: bool,
  env: Map<string, [string, null]>,
  stdio: StdioConfig,
  kill_on_drop: bool,
};

type Child = {
  proc: Proc,
  pid: i64,
  stdin: [Pipe, null],
  stdout: [Pipe, null],
  stderr: [Pipe, null],
};

type ExitStatus = {
  code: [i64, null],
  success: bool,
};

/// Build stdio configuration. Streams inherit from the parent by default.
val stdio: fn(
  ?#stdin: Redirect,
  ?#stdout: Redirect,
  ?#stderr: Redirect
) -> StdioConfig;

/// Build spawn options with default args/env/cwd/stdio settings.
val options: fn(
  ?#args: Array<string>,
  ?#cwd: [string, null],
  ?#clear_env: bool,
  ?#env: Map<string, [string, null]>,
  ?#stdio: StdioConfig,
  ?#kill_on_drop: bool,
  command: string
) -> SpawnOptions;

/// Start a child process using the supplied options. The process handle
/// owns the child lifetime; if kill_on_drop is true, dropping the final
/// handle kills a still-running child.
val spawn: fn(options: SpawnOptions) -> Result<Child, `ProcessError(string)>;

/// Wait until the process exits and return its status. Multiple callers may
/// wait on the same process concurrently.
val wait: fn(proc: Proc) -> Result<ExitStatus, `ProcessError(string)>;

/// Return the OS process identifier assigned when the process was spawned.
val pid: fn(proc: Proc) -> i64;

/// Stop the process if it is still running: signal graceful shutdown
/// (SIGTERM on unix, the shutdown event on Windows), give it #grace to
/// comply, then hard-kill as the backstop. The default #grace of zero
/// is an immediate hard kill. Resolves after the process is dead; a
/// no-op for a process that already exited.
val kill: fn(?#grace: duration, proc: Proc) -> null;

kill stops a running process gracefully: it signals shutdown (SIGTERM on unix, a shutdown event on Windows), gives the process #grace to comply, then hard-kills as the backstop. The default grace of zero is an immediate hard kill. It resolves after the process is dead, and is a no-op for a process that already exited. On Windows a kill_on_drop child is also assigned to a job object, so it is terminated even if the graphix process crashes; a child spawned with kill_on_drop: false is detached and may outlive the graphix process on every platform.

There is no separate status-probe function: wait is the reactive status source. To track running state, give it an initial value:

let child = sys::process::spawn(sys::process::options(
    #args: ["-c", "sleep 0.1"],
    #kill_on_drop: true,
    "/bin/sh"
))$;
let status: [`Running, `Exited(sys::process::ExitStatus)] = `Running;
status <- `Exited(sys::process::wait(child.proc)$);
println("[status]")

status holds `Running until the process exits, then fires exactly once with the exit status — no polling, no race. A wait called after the process has already exited fires immediately, and multiple concurrent waiters are fine.

Example:

{
  use opt;
  let options = sys::process::options(
    #args: ["-c", "printf hello"],
    #stdio: sys::process::stdio(#stdout: `Pipe, #stderr: `Inherit),
    #kill_on_drop: true,
    "/bin/sh"
  );
  let child = sys::process::spawn(options)?;
  let stdout = opt::ok_or(child.stdout, `Null("stdout"))?;
  let out = buffer::to_string(sys::io::Read::read(stdout, u64:1024)?)?;
  let status = sys::process::wait(child.proc)?;
  status.success ~ out
}