pset 0.1.0

Orchestrate a set of child processes: one event stream for their output and their exits
//! Platform plumbing: one kernel queue that waits on pipes and process exits
//! together.
//!
//! Nothing here knows about tags or `Command`s. Each platform module turns
//! its kernel's primitives into the same two types with the same contract,
//! and everything above is written against that contract alone:
//!
//! - [`Poller`] is the queue. `watch_read` registers a descriptor for
//!   level-triggered readability under a caller-chosen token — a descriptor
//!   stays ready until drained or removed, so a caller reading one chunk per
//!   wakeup cannot lose the rest. `watch_exit` arranges for a token to come
//!   out of `wait` at least once after the process exits, even when the
//!   process is already dead (but not reaped) as the watch is made. `wait`
//!   blocks for the next batch of ready tokens.
//! - [`ExitWatch`] is what `watch_exit` returns: the handle through which the
//!   process is signalled (`send_signal`) and its watch removed
//!   ([`Poller::unwatch_exit`]). Signalling through it cannot hit a recycled
//!   pid, provided the child was unreaped when the watch was made and is not
//!   signalled after being reaped — which the set upholds.

use crate::cvt;
#[cfg(target_os = "linux")]
pub use linux::{ExitWatch, Poller};
#[cfg(target_os = "macos")]
pub use macos::{ExitWatch, Poller};
use std::{
    io,
    os::fd::{AsRawFd, BorrowedFd},
};

#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
compile_error!("pset supports Linux (pidfd_open(2) + epoll(7)) and macOS (kqueue(2)) only");

/// Put a descriptor into non-blocking mode.
pub fn set_nonblocking(fd: BorrowedFd<'_>) -> io::Result<()> {
    // SAFETY: plain fcntl on a live descriptor.
    let flags = cvt!(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_GETFL) });
    // SAFETY: as above.
    cvt!(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFL, flags | libc::O_NONBLOCK) });
    Ok(())
}