summaryrefslogtreecommitdiffstats
path: root/vendor/tokio/src/process/unix/mod.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/tokio/src/process/unix/mod.rs
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tokio/src/process/unix/mod.rs')
-rw-r--r--vendor/tokio/src/process/unix/mod.rs135
1 files changed, 108 insertions, 27 deletions
diff --git a/vendor/tokio/src/process/unix/mod.rs b/vendor/tokio/src/process/unix/mod.rs
index fab63dd3d..41857f49c 100644
--- a/vendor/tokio/src/process/unix/mod.rs
+++ b/vendor/tokio/src/process/unix/mod.rs
@@ -1,4 +1,4 @@
-//! Unix handling of child processes
+//! 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
@@ -21,27 +21,26 @@
//! processes in general aren't scalable (e.g. millions) so it shouldn't be that
//! bad in theory...
-pub(crate) mod driver;
-
pub(crate) mod orphan;
use orphan::{OrphanQueue, OrphanQueueImpl, Wait};
mod reap;
use reap::Reaper;
-use crate::io::PollEvented;
+use crate::io::{AsyncRead, AsyncWrite, PollEvented, ReadBuf};
use crate::process::kill::Kill;
use crate::process::SpawnedChild;
-use crate::signal::unix::driver::Handle as SignalHandle;
+use crate::runtime::signal::Handle as SignalHandle;
use crate::signal::unix::{signal, Signal, SignalKind};
use mio::event::Source;
use mio::unix::SourceFd;
-use once_cell::sync::Lazy;
use std::fmt;
use std::fs::File;
use std::future::Future;
use std::io;
+#[cfg(not(tokio_no_as_fd))]
+use std::os::unix::io::{AsFd, BorrowedFd};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::pin::Pin;
use std::process::{Child as StdChild, ExitStatus, Stdio};
@@ -64,25 +63,41 @@ impl Kill for StdChild {
}
}
-static ORPHAN_QUEUE: Lazy<OrphanQueueImpl<StdChild>> = Lazy::new(OrphanQueueImpl::new);
+cfg_not_has_const_mutex_new! {
+ fn get_orphan_queue() -> &'static OrphanQueueImpl<StdChild> {
+ use crate::util::once_cell::OnceCell;
+
+ static ORPHAN_QUEUE: OnceCell<OrphanQueueImpl<StdChild>> = OnceCell::new();
+
+ ORPHAN_QUEUE.get(OrphanQueueImpl::new)
+ }
+}
+
+cfg_has_const_mutex_new! {
+ fn get_orphan_queue() -> &'static OrphanQueueImpl<StdChild> {
+ static ORPHAN_QUEUE: OrphanQueueImpl<StdChild> = OrphanQueueImpl::new();
+
+ &ORPHAN_QUEUE
+ }
+}
pub(crate) struct GlobalOrphanQueue;
impl fmt::Debug for GlobalOrphanQueue {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- ORPHAN_QUEUE.fmt(fmt)
+ get_orphan_queue().fmt(fmt)
}
}
impl GlobalOrphanQueue {
- fn reap_orphans(handle: &SignalHandle) {
- ORPHAN_QUEUE.reap_orphans(handle)
+ pub(crate) fn reap_orphans(handle: &SignalHandle) {
+ get_orphan_queue().reap_orphans(handle)
}
}
impl OrphanQueue<StdChild> for GlobalOrphanQueue {
fn push_orphan(&self, orphan: StdChild) {
- ORPHAN_QUEUE.push_orphan(orphan)
+ get_orphan_queue().push_orphan(orphan)
}
}
@@ -101,9 +116,9 @@ impl fmt::Debug for Child {
pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result<SpawnedChild> {
let mut child = cmd.spawn()?;
- let stdin = stdio(child.stdin.take())?;
- let stdout = stdio(child.stdout.take())?;
- let stderr = stdio(child.stderr.take())?;
+ let stdin = child.stdin.take().map(stdio).transpose()?;
+ let stdout = child.stdout.take().map(stdio).transpose()?;
+ let stderr = child.stderr.take().map(stdio).transpose()?;
let signal = signal(SignalKind::child())?;
@@ -143,7 +158,7 @@ impl Future for Child {
#[derive(Debug)]
pub(crate) struct Pipe {
- // Actually a pipe and not a File. However, we are reusing `File` to get
+ // 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,
}
@@ -169,6 +184,10 @@ impl<'a> io::Write for &'a Pipe {
fn flush(&mut self) -> io::Result<()> {
(&self.fd).flush()
}
+
+ fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+ (&self.fd).write_vectored(bufs)
+ }
}
impl AsRawFd for Pipe {
@@ -177,8 +196,15 @@ impl AsRawFd for Pipe {
}
}
-pub(crate) fn convert_to_stdio(io: PollEvented<Pipe>) -> io::Result<Stdio> {
- let mut fd = io.into_inner()?.fd;
+#[cfg(not(tokio_no_as_fd))]
+impl AsFd for Pipe {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
+ }
+}
+
+pub(crate) fn convert_to_stdio(io: ChildStdio) -> io::Result<Stdio> {
+ let mut fd = io.inner.into_inner()?.fd;
// 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
@@ -213,9 +239,69 @@ impl Source for Pipe {
}
}
-pub(crate) type ChildStdin = PollEvented<Pipe>;
-pub(crate) type ChildStdout = PollEvented<Pipe>;
-pub(crate) type ChildStderr = PollEvented<Pipe>;
+pub(crate) struct ChildStdio {
+ inner: PollEvented<Pipe>,
+}
+
+impl fmt::Debug for ChildStdio {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(fmt)
+ }
+}
+
+impl AsRawFd for ChildStdio {
+ fn as_raw_fd(&self) -> RawFd {
+ self.inner.as_raw_fd()
+ }
+}
+
+#[cfg(not(tokio_no_as_fd))]
+impl AsFd for ChildStdio {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
+ }
+}
+
+impl AsyncWrite for ChildStdio {
+ fn poll_write(
+ self: Pin<&mut Self>,
+ cx: &mut Context<'_>,
+ buf: &[u8],
+ ) -> Poll<io::Result<usize>> {
+ self.inner.poll_write(cx, buf)
+ }
+
+ fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn poll_write_vectored(
+ self: Pin<&mut Self>,
+ cx: &mut Context<'_>,
+ bufs: &[io::IoSlice<'_>],
+ ) -> Poll<Result<usize, io::Error>> {
+ self.inner.poll_write_vectored(cx, bufs)
+ }
+
+ fn is_write_vectored(&self) -> bool {
+ true
+ }
+}
+
+impl AsyncRead for ChildStdio {
+ fn poll_read(
+ self: Pin<&mut Self>,
+ cx: &mut Context<'_>,
+ buf: &mut ReadBuf<'_>,
+ ) -> Poll<io::Result<()>> {
+ // Safety: pipes support reading into uninitialized memory
+ unsafe { self.inner.poll_read(cx, buf) }
+ }
+}
fn set_nonblocking<T: AsRawFd>(fd: &mut T, nonblocking: bool) -> io::Result<()> {
unsafe {
@@ -240,18 +326,13 @@ fn set_nonblocking<T: AsRawFd>(fd: &mut T, nonblocking: bool) -> io::Result<()>
Ok(())
}
-fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Pipe>>>
+pub(super) fn stdio<T>(io: T) -> io::Result<ChildStdio>
where
T: IntoRawFd,
{
- let io = match option {
- Some(io) => io,
- None => return Ok(None),
- };
-
// Set the fd to nonblocking before we pass it to the event loop
let mut pipe = Pipe::from(io);
set_nonblocking(&mut pipe, true)?;
- Ok(Some(PollEvented::new(pipe)?))
+ PollEvented::new(pipe).map(|inner| ChildStdio { inner })
}