summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cc/src/parallel/stderr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cc/src/parallel/stderr.rs')
-rw-r--r--third_party/rust/cc/src/parallel/stderr.rs90
1 files changed, 90 insertions, 0 deletions
diff --git a/third_party/rust/cc/src/parallel/stderr.rs b/third_party/rust/cc/src/parallel/stderr.rs
new file mode 100644
index 0000000000..47fa085dba
--- /dev/null
+++ b/third_party/rust/cc/src/parallel/stderr.rs
@@ -0,0 +1,90 @@
+/// Helpers functions for [ChildStderr].
+use std::{convert::TryInto, process::ChildStderr};
+
+use crate::{Error, ErrorKind};
+
+#[cfg(all(not(unix), not(windows)))]
+compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
+
+#[cfg(unix)]
+fn get_flags(fd: std::os::unix::io::RawFd) -> Result<i32, Error> {
+ let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
+ if flags == -1 {
+ Err(Error::new(
+ ErrorKind::IOError,
+ format!(
+ "Failed to get flags for pipe {}: {}",
+ fd,
+ std::io::Error::last_os_error()
+ ),
+ ))
+ } else {
+ Ok(flags)
+ }
+}
+
+#[cfg(unix)]
+fn set_flags(fd: std::os::unix::io::RawFd, flags: std::os::raw::c_int) -> Result<(), Error> {
+ if unsafe { libc::fcntl(fd, libc::F_SETFL, flags) } == -1 {
+ Err(Error::new(
+ ErrorKind::IOError,
+ format!(
+ "Failed to set flags for pipe {}: {}",
+ fd,
+ std::io::Error::last_os_error()
+ ),
+ ))
+ } else {
+ Ok(())
+ }
+}
+
+#[cfg(unix)]
+pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
+ // On Unix, switch the pipe to non-blocking mode.
+ // On Windows, we have a different way to be non-blocking.
+ let fd = pipe.as_raw_fd();
+
+ let flags = get_flags(fd)?;
+ set_flags(fd, flags | libc::O_NONBLOCK)
+}
+
+pub fn bytes_available(stderr: &mut ChildStderr) -> Result<usize, Error> {
+ let mut bytes_available = 0;
+ #[cfg(windows)]
+ {
+ use crate::windows::windows_sys::PeekNamedPipe;
+ use std::os::windows::io::AsRawHandle;
+ use std::ptr::null_mut;
+ if unsafe {
+ PeekNamedPipe(
+ stderr.as_raw_handle(),
+ null_mut(),
+ 0,
+ null_mut(),
+ &mut bytes_available,
+ null_mut(),
+ )
+ } == 0
+ {
+ return Err(Error::new(
+ ErrorKind::IOError,
+ format!(
+ "PeekNamedPipe failed with {}",
+ std::io::Error::last_os_error()
+ ),
+ ));
+ }
+ }
+ #[cfg(unix)]
+ {
+ use std::os::unix::io::AsRawFd;
+ if unsafe { libc::ioctl(stderr.as_raw_fd(), libc::FIONREAD, &mut bytes_available) } != 0 {
+ return Err(Error::new(
+ ErrorKind::IOError,
+ format!("ioctl failed with {}", std::io::Error::last_os_error()),
+ ));
+ }
+ }
+ Ok(bytes_available.try_into().unwrap())
+}