From 0a631f88e8fd5d347c8297c9114d25382889d395 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 10 Aug 2023 00:04:53 +1000 Subject: [PATCH] process: add `{ChildStd*}::into_owned_{fd, handle}` (#5899) --- tokio/src/doc/os.rs | 3 + tokio/src/process/mod.rs | 140 +++++++++++++++++++--------------- tokio/src/process/unix/mod.rs | 16 +++- tokio/src/process/windows.rs | 18 +++-- 4 files changed, 107 insertions(+), 70 deletions(-) diff --git a/tokio/src/doc/os.rs b/tokio/src/doc/os.rs index 9404d4491f2..cded8b97cc0 100644 --- a/tokio/src/doc/os.rs +++ b/tokio/src/doc/os.rs @@ -11,6 +11,9 @@ pub mod windows { /// See [std::os::windows::io::RawHandle](https://doc.rust-lang.org/std/os/windows/io/type.RawHandle.html) pub type RawHandle = crate::doc::NotDefinedHere; + /// See [std::os::windows::io::OwnedHandle](https://doc.rust-lang.org/std/os/windows/io/struct.OwnedHandle.html) + pub type OwnedHandle = crate::doc::NotDefinedHere; + /// See [std::os::windows::io::AsRawHandle](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html) pub trait AsRawHandle { /// See [std::os::windows::io::AsRawHandle::as_raw_handle](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html#tymethod.as_raw_handle) diff --git a/tokio/src/process/mod.rs b/tokio/src/process/mod.rs index 5ab5647c29b..3672f117afd 100644 --- a/tokio/src/process/mod.rs +++ b/tokio/src/process/mod.rs @@ -259,7 +259,7 @@ use std::os::unix::process::CommandExt; use std::os::windows::process::CommandExt; cfg_windows! { - use crate::os::windows::io::{AsRawHandle, RawHandle, AsHandle, BorrowedHandle}; + use crate::os::windows::io::{AsRawHandle, RawHandle}; } /// This structure mimics the API of [`std::process::Command`] found in the standard library, but @@ -1447,84 +1447,100 @@ impl TryInto for ChildStderr { } #[cfg(unix)] +#[cfg_attr(docsrs, doc(cfg(unix)))] mod sys { - use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; + use std::{ + io, + os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}, + }; use super::{ChildStderr, ChildStdin, ChildStdout}; - impl AsRawFd for ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } - } - - impl AsFd for ChildStdin { - fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } - } - } - - impl AsRawFd for ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } - } + macro_rules! impl_traits { + ($type:ty) => { + impl $type { + /// Convert into [`OwnedFd`]. + pub fn into_owned_fd(self) -> io::Result { + self.inner.into_owned_fd() + } + } - impl AsFd for ChildStdout { - fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } - } - } + impl AsRawFd for $type { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } + } - impl AsRawFd for ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } + impl AsFd for $type { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } + } + } + }; } - impl AsFd for ChildStderr { - fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } - } - } + impl_traits!(ChildStdin); + impl_traits!(ChildStdout); + impl_traits!(ChildStderr); } -cfg_windows! { - impl AsRawHandle for ChildStdin { - fn as_raw_handle(&self) -> RawHandle { - self.inner.as_raw_handle() - } - } +#[cfg(any(windows, docsrs))] +#[cfg_attr(docsrs, doc(cfg(windows)))] +mod windows { + use super::*; + use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, OwnedHandle, RawHandle}; + + #[cfg(not(docsrs))] + macro_rules! impl_traits { + ($type:ty) => { + impl $type { + /// Convert into [`OwnedHandle`]. + pub fn into_owned_handle(self) -> io::Result { + self.inner.into_owned_handle() + } + } - impl AsHandle for ChildStdin { - fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } - } - } + impl AsRawHandle for $type { + fn as_raw_handle(&self) -> RawHandle { + self.inner.as_raw_handle() + } + } - impl AsRawHandle for ChildStdout { - fn as_raw_handle(&self) -> RawHandle { - self.inner.as_raw_handle() - } + impl AsHandle for $type { + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } + } + }; } - impl AsHandle for ChildStdout { - fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } - } - } + #[cfg(docsrs)] + macro_rules! impl_traits { + ($type:ty) => { + impl $type { + /// Convert into [`OwnedHandle`]. + pub fn into_owned_handle(self) -> io::Result { + todo!("For doc generation only") + } + } - impl AsRawHandle for ChildStderr { - fn as_raw_handle(&self) -> RawHandle { - self.inner.as_raw_handle() - } - } + impl AsRawHandle for $type { + fn as_raw_handle(&self) -> RawHandle { + todo!("For doc generation only") + } + } - impl AsHandle for ChildStderr { - fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } - } + impl AsHandle for $type { + fn as_handle(&self) -> BorrowedHandle<'_> { + todo!("For doc generation only") + } + } + }; } + + impl_traits!(ChildStdin); + impl_traits!(ChildStdout); + impl_traits!(ChildStderr); } #[cfg(all(test, not(loom)))] diff --git a/tokio/src/process/unix/mod.rs b/tokio/src/process/unix/mod.rs index 36991bf971f..b9c2d78e80d 100644 --- a/tokio/src/process/unix/mod.rs +++ b/tokio/src/process/unix/mod.rs @@ -39,7 +39,7 @@ use std::fmt; use std::fs::File; use std::future::Future; use std::io; -use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +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; @@ -200,7 +200,7 @@ impl AsFd for Pipe { } } -pub(crate) fn convert_to_stdio(io: ChildStdio) -> io::Result { +fn convert_to_blocking_file(io: ChildStdio) -> io::Result { let mut fd = io.inner.into_inner()?.fd; // Ensure that the fd to be inherited is set to *blocking* mode, as this @@ -209,7 +209,11 @@ pub(crate) fn convert_to_stdio(io: ChildStdio) -> io::Result { // change it to nonblocking mode. set_nonblocking(&mut fd, false)?; - Ok(Stdio::from(fd)) + Ok(fd) +} + +pub(crate) fn convert_to_stdio(io: ChildStdio) -> io::Result { + convert_to_blocking_file(io).map(Stdio::from) } impl Source for Pipe { @@ -240,6 +244,12 @@ pub(crate) struct ChildStdio { inner: PollEvented, } +impl ChildStdio { + pub(super) fn into_owned_fd(self) -> io::Result { + convert_to_blocking_file(self).map(OwnedFd::from) + } +} + impl fmt::Debug for ChildStdio { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(fmt) diff --git a/tokio/src/process/windows.rs b/tokio/src/process/windows.rs index eb412cdc55f..792a9c9610b 100644 --- a/tokio/src/process/windows.rs +++ b/tokio/src/process/windows.rs @@ -24,7 +24,7 @@ use std::fmt; use std::fs::File as StdFile; use std::future::Future; use std::io; -use std::os::windows::prelude::{AsRawHandle, IntoRawHandle, RawHandle}; +use std::os::windows::prelude::{AsRawHandle, IntoRawHandle, OwnedHandle, RawHandle}; use std::pin::Pin; use std::process::Stdio; use std::process::{Child as StdChild, Command as StdCommand, ExitStatus}; @@ -195,6 +195,12 @@ pub(crate) struct ChildStdio { io: Blocking, } +impl ChildStdio { + pub(super) fn into_owned_handle(self) -> io::Result { + convert_to_file(self).map(OwnedHandle::from) + } +} + impl AsRawHandle for ChildStdio { fn as_raw_handle(&self) -> RawHandle { self.raw.as_raw_handle() @@ -240,13 +246,15 @@ where Ok(ChildStdio { raw, io }) } -pub(crate) fn convert_to_stdio(child_stdio: ChildStdio) -> io::Result { +fn convert_to_file(child_stdio: ChildStdio) -> io::Result { let ChildStdio { raw, io } = child_stdio; drop(io); // Try to drop the Arc count here - Arc::try_unwrap(raw) - .or_else(|raw| duplicate_handle(&*raw)) - .map(Stdio::from) + Arc::try_unwrap(raw).or_else(|raw| duplicate_handle(&*raw)) +} + +pub(crate) fn convert_to_stdio(child_stdio: ChildStdio) -> io::Result { + convert_to_file(child_stdio).map(Stdio::from) } fn duplicate_handle(io: &T) -> io::Result {