child
import std::process::child; · source
Child
type struct Child {
stdin: Option<ChildStdin>;
stdout: Option<ChildStdout>;
stderr: Option<ChildStderr>;
static new(pid: i32, handle: u64, stdin: Option<ChildStdin>, stdout: Option<ChildStdout>, stderr: Option<ChildStderr>) -> Child;
id(&this) -> i32;
wait(mut &this) -> Result<ExitStatus, IoError>;
async join(mut &this) -> Result<ExitStatus, IoError>;
try_wait(mut &this) -> Result<Option<ExitStatus>, IoError>;
kill(&this) -> Result<(), IoError>;
send_signal(&this, sig: Signal) -> Result<(), IoError>;
}
A running subprocess, produced by spawn. It holds the pid (private, behind id()) and whichever pipe ends you asked for.
| Method | Returns | Notes |
|---|---|---|
id() | i32 | |
wait() | Result<ExitStatus, IoError> | Blocks. Closes stdin first so the child sees EOF. |
join() | async ExitStatus | The non-blocking wait: parks on the reactor (a pidfd on Linux) or the blocking pool. |
try_wait() | Result<Option<ExitStatus>, IoError> | Ok(None) means still running. |
kill() | Result<(), IoError> | SIGKILL on POSIX. Does not wait. |
send_signal(sig) | Result<(), IoError> |
wait closing stdin first is deliberate: it is deadlock-avoidant for a child that reads all of stdin before writing anything to stdout. join does not touch the pipes, so a child that writes more than a pipe buffer holds must have its stdout / stderr drained while you await — the same hazard, and the reason Command::collect drains first.
The pipe ends
type struct ChildStdin {
fd: i32;
static from_fd(raw_fd: i32) -> ChildStdin;
}
type struct ChildStdout {
fd: i32;
static from_fd(raw_fd: i32) -> ChildStdout;
}
type struct ChildStderr {
fd: i32;
static from_fd(raw_fd: i32) -> ChildStderr;
}
The parent's ends of the pipes a Stdio::Piped configuration created. ChildStdin implements Write; ChildStdout and ChildStderr implement Read. Dropping ChildStdin closes the pipe, which is what signals EOF to the child.
Reaping
Every Child should have wait — or kill then wait — called before it drops.
Child::drop closes any captured pipe ends and makes a non-blocking best-effort reap. If the child has already exited, its zombie is released there. If it is still running, a destructor cannot block, so the child stays detached and reaping it remains your responsibility. That closes the common "spawn, child finishes, drop without wait" leak without ever blocking. Cancelling a join mid-wait leaves the child in exactly this state.
Trait implementations
implement trait Drop for struct Child
implement trait Write for struct ChildStdin
implement trait Drop for struct ChildStdin
implement trait Read for struct ChildStdout
implement trait Drop for struct ChildStdout
implement trait Read for struct ChildStderr
implement trait Drop for struct ChildStderr
ExitStatus
type struct ExitStatus {
code: i32;
signal: i32;
signaled: boolean;
success(&this) -> boolean;
exit_code(&this) -> Option<i32>;
terminating_signal(&this) -> Option<i32>;
}
POSIX packs a normal exit and a signal death into one status word; ExitStatus is the decoded form.
| Method | Returns | Notes |
|---|---|---|
success() | boolean | Exited with status 0. |
exit_code() | Option<i32> | None if killed by a signal. |
terminating_signal() | Option<i32> | Some if killed by a signal. |