Skip to content

Commit b030a29

Browse files
Vendor dependency os_pipe (#822)
Co-authored-by: Josh Triplett <[email protected]>
1 parent 163eb8e commit b030a29

File tree

5 files changed

+188
-16
lines changed

5 files changed

+188
-16
lines changed

Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ edition = "2018"
1919

2020
[dependencies]
2121
jobserver = { version = "0.1.16", optional = true }
22-
os_pipe = "1"
22+
23+
[target.'cfg(unix)'.dependencies]
24+
libc = "0.2.62"
25+
26+
[target.'cfg(windows)'.dependencies]
27+
windows-sys = { version = "0.48.0", features = ["Win32_Foundation", "Win32_System_Pipes", "Win32_Security"] }
2328

2429
[features]
2530
parallel = ["jobserver"]

src/lib.rs

+9-15
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,16 @@ use std::collections::{hash_map, HashMap};
6161
use std::env;
6262
use std::ffi::{OsStr, OsString};
6363
use std::fmt::{self, Display, Formatter};
64-
use std::fs;
64+
use std::fs::{self, File};
6565
use std::hash::Hasher;
6666
use std::io::{self, BufRead, BufReader, Read, Write};
6767
use std::path::{Component, Path, PathBuf};
6868
use std::process::{Child, Command, Stdio};
6969
use std::sync::{Arc, Mutex};
7070
use std::thread::{self, JoinHandle};
7171

72+
mod os_pipe;
73+
7274
// These modules are all glue to support reading the MSVC version from
7375
// the registry and from COM interfaces
7476
#[cfg(windows)]
@@ -3494,11 +3496,7 @@ fn wait_on_child(cmd: &Command, program: &str, child: &mut Child) -> Result<(),
34943496
}
34953497
}
34963498

3497-
fn run_inner(
3498-
cmd: &mut Command,
3499-
program: &str,
3500-
pipe_writer: os_pipe::PipeWriter,
3501-
) -> Result<(), Error> {
3499+
fn run_inner(cmd: &mut Command, program: &str, pipe_writer: File) -> Result<(), Error> {
35023500
let mut child = spawn(cmd, program, pipe_writer)?;
35033501
wait_on_child(cmd, program, &mut child)
35043502
}
@@ -3529,11 +3527,7 @@ fn run_output(cmd: &mut Command, program: &str) -> Result<Vec<u8>, Error> {
35293527
Ok(stdout)
35303528
}
35313529

3532-
fn spawn(
3533-
cmd: &mut Command,
3534-
program: &str,
3535-
pipe_writer: os_pipe::PipeWriter,
3536-
) -> Result<Child, Error> {
3530+
fn spawn(cmd: &mut Command, program: &str, pipe_writer: File) -> Result<Child, Error> {
35373531
struct ResetStderr<'cmd>(&'cmd mut Command);
35383532

35393533
impl Drop for ResetStderr<'_> {
@@ -3773,7 +3767,7 @@ impl AsmFileExt {
37733767

37743768
struct PrintThread {
37753769
handle: Option<JoinHandle<()>>,
3776-
pipe_writer: Option<os_pipe::PipeWriter>,
3770+
pipe_writer: Option<File>,
37773771
}
37783772

37793773
impl PrintThread {
@@ -3804,14 +3798,14 @@ impl PrintThread {
38043798
})
38053799
}
38063800

3807-
fn pipe_writer(&mut self) -> &mut Option<os_pipe::PipeWriter> {
3801+
fn pipe_writer(&mut self) -> &mut Option<File> {
38083802
&mut self.pipe_writer
38093803
}
38103804

3811-
fn pipe_writer_cloned(&self) -> Result<Option<os_pipe::PipeWriter>, Error> {
3805+
fn pipe_writer_cloned(&self) -> Result<Option<File>, Error> {
38123806
self.pipe_writer
38133807
.as_ref()
3814-
.map(os_pipe::PipeWriter::try_clone)
3808+
.map(File::try_clone)
38153809
.transpose()
38163810
.map_err(From::from)
38173811
}

src/os_pipe.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! Adapted from:
2+
//! - https://doc.rust-lang.org/src/std/sys/unix/pipe.rs.html
3+
//! - https://doc.rust-lang.org/src/std/sys/unix/fd.rs.html#385
4+
//! - https://github.com/rust-lang/rust/blob/master/library/std/src/sys/mod.rs#L57
5+
//! - https://github.com/oconnor663/os_pipe.rs
6+
use std::fs::File;
7+
8+
/// Open a new pipe and return a pair of [`File`] objects for the reader and writer.
9+
///
10+
/// This corresponds to the `pipe2` library call on Posix and the
11+
/// `CreatePipe` library call on Windows (though these implementation
12+
/// details might change). These pipes are non-inheritable, so new child
13+
/// processes won't receive a copy of them unless they're explicitly
14+
/// passed as stdin/stdout/stderr.
15+
pub fn pipe() -> std::io::Result<(File, File)> {
16+
sys::pipe()
17+
}
18+
19+
#[cfg(unix)]
20+
#[path = "os_pipe/unix.rs"]
21+
mod sys;
22+
23+
#[cfg(windows)]
24+
#[path = "os_pipe/windows.rs"]
25+
mod sys;
26+
27+
#[cfg(all(not(unix), not(windows)))]
28+
compile_error!("Only unix and windows support os_pipe!");

src/os_pipe/unix.rs

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use std::{
2+
fs::File,
3+
io,
4+
os::{raw::c_int, unix::io::FromRawFd},
5+
};
6+
7+
pub(super) fn pipe() -> io::Result<(File, File)> {
8+
let mut fds = [0; 2];
9+
10+
// The only known way right now to create atomically set the CLOEXEC flag is
11+
// to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
12+
// and musl 0.9.3, and some other targets also have it.
13+
#[cfg(any(
14+
target_os = "dragonfly",
15+
target_os = "freebsd",
16+
target_os = "linux",
17+
target_os = "netbsd",
18+
target_os = "openbsd",
19+
target_os = "redox"
20+
))]
21+
{
22+
unsafe {
23+
cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
24+
}
25+
}
26+
27+
#[cfg(not(any(
28+
target_os = "dragonfly",
29+
target_os = "freebsd",
30+
target_os = "linux",
31+
target_os = "netbsd",
32+
target_os = "openbsd",
33+
target_os = "redox"
34+
)))]
35+
{
36+
unsafe {
37+
cvt(libc::pipe(fds.as_mut_ptr()))?;
38+
}
39+
40+
cloexec::set_cloexec(fds[0])?;
41+
cloexec::set_cloexec(fds[1])?;
42+
}
43+
44+
unsafe { Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1]))) }
45+
}
46+
47+
fn cvt(t: c_int) -> io::Result<c_int> {
48+
if t == -1 {
49+
Err(io::Error::last_os_error())
50+
} else {
51+
Ok(t)
52+
}
53+
}
54+
55+
#[cfg(not(any(
56+
target_os = "dragonfly",
57+
target_os = "freebsd",
58+
target_os = "linux",
59+
target_os = "netbsd",
60+
target_os = "openbsd",
61+
target_os = "redox"
62+
)))]
63+
mod cloexec {
64+
use super::{c_int, cvt, io};
65+
66+
#[cfg(not(any(
67+
target_env = "newlib",
68+
target_os = "solaris",
69+
target_os = "illumos",
70+
target_os = "emscripten",
71+
target_os = "fuchsia",
72+
target_os = "l4re",
73+
target_os = "linux",
74+
target_os = "haiku",
75+
target_os = "redox",
76+
target_os = "vxworks",
77+
target_os = "nto",
78+
)))]
79+
pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> {
80+
unsafe {
81+
cvt(libc::ioctl(fd, libc::FIOCLEX))?;
82+
}
83+
84+
Ok(())
85+
}
86+
87+
#[cfg(any(
88+
all(
89+
target_env = "newlib",
90+
not(any(target_os = "espidf", target_os = "horizon"))
91+
),
92+
target_os = "solaris",
93+
target_os = "illumos",
94+
target_os = "emscripten",
95+
target_os = "fuchsia",
96+
target_os = "l4re",
97+
target_os = "linux",
98+
target_os = "haiku",
99+
target_os = "redox",
100+
target_os = "vxworks",
101+
target_os = "nto",
102+
))]
103+
pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> {
104+
unsafe {
105+
let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?;
106+
let new = previous | libc::FD_CLOEXEC;
107+
if new != previous {
108+
cvt(libc::fcntl(fd, libc::F_SETFD, new))?;
109+
}
110+
}
111+
112+
Ok(())
113+
}
114+
115+
// FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
116+
// because neither supports spawning processes.
117+
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
118+
pub(super) fn set_cloexec(_fd: c_int) -> io::Result<()> {
119+
Ok(())
120+
}
121+
}

src/os_pipe/windows.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use std::{fs::File, io, os::windows::prelude::*, ptr};
2+
use windows_sys::Win32::{Foundation::INVALID_HANDLE_VALUE, System::Pipes::CreatePipe};
3+
4+
/// NOTE: These pipes do not support IOCP.
5+
///
6+
/// If IOCP is needed, then you might want to emulate
7+
/// anonymous pipes with CreateNamedPipe, as Rust's stdlib does.
8+
pub(super) fn pipe() -> io::Result<(File, File)> {
9+
let mut read_pipe = INVALID_HANDLE_VALUE;
10+
let mut write_pipe = INVALID_HANDLE_VALUE;
11+
12+
let ret = unsafe { CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) };
13+
14+
if ret == 0 {
15+
Err(io::Error::last_os_error())
16+
} else {
17+
unsafe {
18+
Ok((
19+
File::from_raw_handle(read_pipe as RawHandle),
20+
File::from_raw_handle(write_pipe as RawHandle),
21+
))
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)