Skip to content

Commit

Permalink
Auto merge of rust-lang#127153 - NobodyXu:pipe, r=jhpratt
Browse files Browse the repository at this point in the history
Initial implementation of anonymous_pipe API

ACP completed in rust-lang/libs-team#375
Tracking issue: rust-lang#127154

try-job: x86_64-msvc
try-job: i686-mingw
  • Loading branch information
bors committed Jul 22, 2024
2 parents aee3dc4 + 44071a0 commit 144ce10
Show file tree
Hide file tree
Showing 15 changed files with 522 additions and 16 deletions.
56 changes: 44 additions & 12 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ core = { path = "../core", public = true }
compiler_builtins = { version = "0.1.105" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] }
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
hashbrown = { version = "0.14", default-features = false, features = [
'rustc-dep-of-std',
] }
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [
'rustc-dep-of-std',
] }

# Dependencies of the `backtrace` crate
rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
Expand All @@ -31,13 +35,27 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
addr2line = { version = "0.22.0", optional = true, default-features = false }

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
libc = { version = "0.2.153", default-features = false, features = [
'rustc-dep-of-std',
], public = true }

[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
object = { version = "0.36.0", default-features = false, optional = true, features = [
'read_core',
'elf',
'macho',
'pe',
'unaligned',
'archive',
] }

[target.'cfg(target_os = "aix")'.dependencies]
object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] }
object = { version = "0.36.0", default-features = false, optional = true, features = [
'read_core',
'xcoff',
'unaligned',
'archive',
] }

[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
Expand All @@ -47,23 +65,29 @@ rand_xorshift = "0.3.0"
dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }

[target.x86_64-fortanix-unknown-sgx.dependencies]
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true }
fortanix-sgx-abi = { version = "0.5.0", features = [
'rustc-dep-of-std',
], public = true }

[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true }
hermit-abi = { version = "0.4.0", features = [
'rustc-dep-of-std',
], public = true }

[target.'cfg(target_os = "wasi")'.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
wasi = { version = "0.11.0", features = [
'rustc-dep-of-std',
], default-features = false }

[target.'cfg(target_os = "uefi")'.dependencies]
r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }

[features]
backtrace = [
'addr2line/rustc-dep-of-std',
'object/rustc-dep-of-std',
'miniz_oxide/rustc-dep-of-std',
'addr2line/rustc-dep-of-std',
'object/rustc-dep-of-std',
'miniz_oxide/rustc-dep-of-std',
]

panic-unwind = ["panic_unwind"]
Expand All @@ -77,7 +101,10 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
system-llvm-libunwind = ["unwind/system-llvm-libunwind"]

# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = ["core/panic_immediate_abort", "alloc/panic_immediate_abort"]
panic_immediate_abort = [
"core/panic_immediate_abort",
"alloc/panic_immediate_abort",
]
# Choose algorithms that are optimized for binary size instead of runtime performance
optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]

Expand All @@ -97,6 +124,11 @@ threads = 125
# Maximum heap size
heap_size = 0x8000000

[[test]]
name = "pipe-subprocess"
path = "tests/pipe_subprocess.rs"
harness = false

[[bench]]
name = "stdbenches"
path = "benches/lib.rs"
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,9 @@ pub use core::{
module_path, option_env, stringify, trace_macros,
};

#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub use crate::sys::anonymous_pipe as pipe;

#[unstable(
feature = "concat_bytes",
issue = "87555",
Expand Down
146 changes: 146 additions & 0 deletions library/std/src/sys/anonymous_pipe/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//! Module for anonymous pipe
//!
//! ```
//! #![feature(anonymous_pipe)]
//!
//! # #[cfg(miri)] fn main() {}
//! # #[cfg(not(miri))]
//! # fn main() -> std::io::Result<()> {
//! let (reader, writer) = std::pipe::pipe()?;
//! # Ok(())
//! # }
//! ```

cfg_if::cfg_if! {
if #[cfg(unix)] {
mod unix;
use unix::{AnonPipe, pipe as pipe_inner};

#[cfg(all(test, not(miri)))]
mod tests;
} else if #[cfg(windows)] {
mod windows;
use windows::{AnonPipe, pipe as pipe_inner};

#[cfg(all(test, not(miri)))]
mod tests;
} else {
mod unsupported;
use unsupported::{AnonPipe, pipe as pipe_inner};
}
}

use crate::io;

/// Create anonymous pipe that is close-on-exec and blocking.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[inline]
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
}

/// Read end of the anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeReader(AnonPipe);

/// Write end of the anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeWriter(AnonPipe);

impl PipeReader {
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}

impl PipeWriter {
/// Create a new [`PipeWriter`] instance that shares the same underlying file description.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}

fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}

#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}

fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}

#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}
18 changes: 18 additions & 0 deletions library/std/src/sys/anonymous_pipe/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use super::*;
use crate::io::{Read, Write};

#[test]
fn pipe_creation_clone_and_rw() {
let (rx, tx) = pipe().unwrap();

tx.try_clone().unwrap().write_all(b"12345").unwrap();
drop(tx);

let mut rx2 = rx.try_clone().unwrap();
drop(rx);

let mut s = String::new();
rx2.read_to_string(&mut s).unwrap();
drop(rx2);
assert_eq!(s, "12345");
}
103 changes: 103 additions & 0 deletions library/std/src/sys/anonymous_pipe/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use super::*;

use crate::{
os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
process::Stdio,
sys::{fd::FileDesc, pipe::anon_pipe},
sys_common::{FromInner, IntoInner},
};

pub(super) type AnonPipe = FileDesc;

#[inline]
pub(super) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner()))
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsFd for PipeReader {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawFd for PipeReader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for OwnedFd {
fn from(pipe: PipeReader) -> Self {
FileDesc::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawFd for PipeReader {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self(FileDesc::from_raw_fd(raw_fd))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawFd for PipeReader {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for Stdio {
fn from(pipe: PipeReader) -> Self {
Self::from(OwnedFd::from(pipe))
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsFd for PipeWriter {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawFd for PipeWriter {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for OwnedFd {
fn from(pipe: PipeWriter) -> Self {
FileDesc::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawFd for PipeWriter {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self(FileDesc::from_raw_fd(raw_fd))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawFd for PipeWriter {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for Stdio {
fn from(pipe: PipeWriter) -> Self {
Self::from(OwnedFd::from(pipe))
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedFd> for PipeReader {
fn from(owned_fd: OwnedFd) -> Self {
Self(FileDesc::from_inner(owned_fd))
}
}

#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedFd> for PipeWriter {
fn from(owned_fd: OwnedFd) -> Self {
Self(FileDesc::from_inner(owned_fd))
}
}
Loading

0 comments on commit 144ce10

Please sign in to comment.