//! Unix handling of child processes. //! //! Right now the only "fancy" thing about this is how we implement the //! `Future` implementation on `Child` to get the exit status. Unix offers //! no way to register a child with epoll, and the only real way to get a //! notification when a process exits is the SIGCHLD signal. //! //! Signal handling in general is *super* hairy and complicated, and it's even //! more complicated here with the fact that signals are coalesced, so we may //! not get a SIGCHLD-per-child. //! //! Our best approximation here is to check *all spawned processes* for all //! SIGCHLD signals received. To do that we create a `Signal`, implemented in //! the `tokio-net` crate, which is a stream over signals being received. //! //! Later when we poll the process's exit status we simply check to see if a //! SIGCHLD has happened since we last checked, and while that returns "yes" we //! keep trying. //! //! Note that this means that this isn't really scalable, but then again //! processes in general aren't scalable (e.g. millions) so it shouldn't be that //! bad in theory...
pub(crate) mod orphan; use orphan::{OrphanQueue, OrphanQueueImpl, Wait};
mod reap; use reap::Reaper;
#[cfg(all(target_os = "linux", feature = "rt"))] mod pidfd_reaper;
use mio::event::Source; use mio::unix::SourceFd; use std::fmt; use std::fs::File; use std::future::Future; use std::io; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use std::pin::Pin; use std::process::{Child as StdChild, ExitStatus, Stdio}; use std::task::Context; use std::task::Poll;
#[derive(Debug)] pub(crate) struct Pipe { // Actually a pipe is not a File. However, we are reusing `File` to get // close on drop. This is a similar trick as `mio`.
fd: File,
}
// Ensure that the fd to be inherited is set to *blocking* mode, as this // is the default that virtually all programs expect to have. Those // programs that know how to work with nonblocking stdio will know how to // change it to nonblocking mode.
set_nonblocking(&mut fd, false)?;
fn set_nonblocking<T: AsRawFd>(fd: &mut T, nonblocking: bool) -> io::Result<()> { unsafe { let fd = fd.as_raw_fd(); let previous = libc::fcntl(fd, libc::F_GETFL); if previous == -1 { return Err(io::Error::last_os_error());
}
let new = if nonblocking {
previous | libc::O_NONBLOCK
} else {
previous & !libc::O_NONBLOCK
};
let r = libc::fcntl(fd, libc::F_SETFL, new); if r == -1 { return Err(io::Error::last_os_error());
}
}
Ok(())
}
pub(super) fn stdio<T>(io: T) -> io::Result<ChildStdio> where
T: IntoRawFd,
{ // Set the fd to nonblocking before we pass it to the event loop letmut pipe = Pipe::from(io);
set_nonblocking(&mut pipe, true)?;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.