Skip to content

Commit df59d43

Browse files
authored
Fix setting O_NONBLOCK in parallel::stderr::set_non_blocking (#946)
1 parent a891a57 commit df59d43

File tree

3 files changed

+30
-39
lines changed

3 files changed

+30
-39
lines changed

src/command_helpers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ impl StderrForwarder {
167167
pub(crate) fn set_non_blocking(&mut self) -> Result<(), Error> {
168168
assert!(!self.is_non_blocking);
169169

170-
if let Some((stderr, _)) = self.inner.as_mut() {
170+
#[cfg(unix)]
171+
if let Some((stderr, _)) = self.inner.as_ref() {
171172
crate::parallel::stderr::set_non_blocking(stderr)?;
172173
}
173174

src/parallel/job_token/unix.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use std::{
1010
path::Path,
1111
};
1212

13+
use crate::parallel::stderr::set_non_blocking;
14+
1315
pub(super) struct JobServerClient {
1416
read: File,
1517
write: Option<File>,
@@ -35,7 +37,7 @@ impl JobServerClient {
3537
if is_pipe(&file)? {
3638
// File in Rust is always closed-on-exec as long as it's opened by
3739
// `File::open` or `fs::OpenOptions::open`.
38-
set_nonblocking(&file)?;
40+
set_non_blocking(&file).ok()?;
3941

4042
Some(Self {
4143
read: file,
@@ -79,8 +81,8 @@ impl JobServerClient {
7981
let write = write.try_clone().ok()?;
8082

8183
// Set read and write end to nonblocking
82-
set_nonblocking(&read)?;
83-
set_nonblocking(&write)?;
84+
set_non_blocking(&read).ok()?;
85+
set_non_blocking(&write).ok()?;
8486

8587
Some(Self {
8688
read,
@@ -135,21 +137,6 @@ impl JobServerClient {
135137
}
136138
}
137139

138-
fn set_nonblocking(file: &File) -> Option<()> {
139-
// F_SETFL can only set the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and
140-
// O_NONBLOCK flags.
141-
//
142-
// For pipe, only O_NONBLOCK is meaningful, so it is ok to
143-
// not issue a F_GETFL fcntl syscall.
144-
let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK) };
145-
146-
if ret == -1 {
147-
None
148-
} else {
149-
Some(())
150-
}
151-
}
152-
153140
fn cvt(t: c_int) -> io::Result<c_int> {
154141
if t == -1 {
155142
Err(io::Error::last_os_error())

src/parallel/stderr.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,32 @@ use crate::{Error, ErrorKind};
66
#[cfg(all(not(unix), not(windows)))]
77
compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
88

9-
#[allow(unused_variables)]
10-
pub fn set_non_blocking(stderr: &mut ChildStderr) -> Result<(), Error> {
9+
#[cfg(unix)]
10+
pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
1111
// On Unix, switch the pipe to non-blocking mode.
1212
// On Windows, we have a different way to be non-blocking.
13-
#[cfg(unix)]
14-
{
15-
use std::os::unix::io::AsRawFd;
16-
let fd = stderr.as_raw_fd();
17-
debug_assert_eq!(
18-
unsafe { libc::fcntl(fd, libc::F_GETFL, 0) },
19-
0,
20-
"stderr should have no flags set"
21-
);
13+
let fd = pipe.as_raw_fd();
14+
let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
15+
if flags == -1 {
16+
return Err(Error::new(
17+
ErrorKind::IOError,
18+
format!(
19+
"Failed to get flags for pipe {}: {}",
20+
fd,
21+
std::io::Error::last_os_error()
22+
),
23+
));
24+
}
2225

23-
if unsafe { libc::fcntl(fd, libc::F_SETFL, libc::O_NONBLOCK) } != 0 {
24-
return Err(Error::new(
25-
ErrorKind::IOError,
26-
format!(
27-
"Failed to set flags for child stderr: {}",
28-
std::io::Error::last_os_error()
29-
),
30-
));
31-
}
26+
if unsafe { libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 {
27+
return Err(Error::new(
28+
ErrorKind::IOError,
29+
format!(
30+
"Failed to set flags for pipe {}: {}",
31+
fd,
32+
std::io::Error::last_os_error()
33+
),
34+
));
3235
}
3336

3437
Ok(())

0 commit comments

Comments
 (0)