Files
2026-08-01 16:11:49 +03:00

38 lines
2.4 KiB
Markdown

## `sigchld` [![Actions Status](https://github.com/oconnor663/sigchld.rs/workflows/tests/badge.svg)](https://github.com/oconnor663/sigchld.rs/actions) [![crates.io](https://img.shields.io/crates/v/sigchld.svg)](https://crates.io/crates/sigchld) [![docs.rs](https://docs.rs/sigchld/badge.svg)](https://docs.rs/sigchld)
This crate is a low-level building block for child process management. Unix doesn't provide a
portable API for waiting for a child process to exit _with a timeout_. (Linux has `pidfd`, but
there's no equivalent on e.g. macOS.) The next best thing is waiting for the `SIGCHLD` signal,
but Unix signal handling is complicated and error-prone. This crate implements `SIGCHLD`
handling using [`signal_hook`] internally, for compatibility with other Rust signal handling
libraries. It allows any number of threads to wait for `SIGCHLD` with an optional timeout.
Note that `SIGCHLD` indicates that _any_ child process has exited, but there's no reliable way
to know _which_ child it was. You generally need to [poll your child process][try_wait] in a
loop, and wait again if it hasn't exited yet. This is still a bit error-prone, and most
applications will prefer a higher-level API that does this loop internally, like
[`shared_child`](https://docs.rs/shared_child) or [`duct`](https://docs.rs/duct).
This crate only supports Unix and doesn't build on Windows. Portable callers need to put this
crate in the `[target.'cfg(unix)'.dependencies]` section of their `Cargo.toml` and only use it
inside of `#[cfg(unix)]` blocks or similar.
## Example
```rust
let mut waiter = sigchld::Waiter::new()?;
// If SIGCHLD arrives after this point, the Waiter will buffer it.
let mut child = std::process::Command::new("sleep").arg("1").spawn()?;
// Block until *any* child exits. See also `wait_timeout` and `wait_deadline`.
waiter.wait()?;
// There's only one child process in this example, so we know that it exited. But in general
// we might not know which child woke us up, and in that case we'd need to wait and check in a
// loop. See the Waiter examples.
assert!(child.try_wait()?.is_some(), "sleep has exited");
```
[`signal_hook`]: https://docs.rs/signal-hook
[try_wait]: https://doc.rust-lang.org/std/process/struct.Child.html#method.try_wait
[`wait_timeout`]: https://docs.rs/shared_child/latest/shared_child/struct.SharedChild.html#method.wait_timeout
[`wait_deadline`]: https://docs.rs/shared_child/latest/shared_child/struct.SharedChild.html#method.wait_deadline