cc/parallel/
stderr.rs
1#![cfg_attr(target_family = "wasm", allow(unused))]
2use std::{convert::TryInto, process::ChildStderr};
4
5use crate::{Error, ErrorKind};
6
7#[cfg(all(not(unix), not(windows), not(target_family = "wasm")))]
8compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
9
10#[cfg(unix)]
11fn get_flags(fd: std::os::unix::io::RawFd) -> Result<i32, Error> {
12 let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
13 if flags == -1 {
14 Err(Error::new(
15 ErrorKind::IOError,
16 format!(
17 "Failed to get flags for pipe {}: {}",
18 fd,
19 std::io::Error::last_os_error()
20 ),
21 ))
22 } else {
23 Ok(flags)
24 }
25}
26
27#[cfg(unix)]
28fn set_flags(fd: std::os::unix::io::RawFd, flags: std::os::raw::c_int) -> Result<(), Error> {
29 if unsafe { libc::fcntl(fd, libc::F_SETFL, flags) } == -1 {
30 Err(Error::new(
31 ErrorKind::IOError,
32 format!(
33 "Failed to set flags for pipe {}: {}",
34 fd,
35 std::io::Error::last_os_error()
36 ),
37 ))
38 } else {
39 Ok(())
40 }
41}
42
43#[cfg(unix)]
44pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
45 let fd = pipe.as_raw_fd();
48
49 let flags = get_flags(fd)?;
50 set_flags(fd, flags | libc::O_NONBLOCK)
51}
52
53pub fn bytes_available(stderr: &mut ChildStderr) -> Result<usize, Error> {
54 let mut bytes_available = 0;
55 #[cfg(windows)]
56 {
57 use crate::windows::windows_sys::PeekNamedPipe;
58 use std::os::windows::io::AsRawHandle;
59 use std::ptr::null_mut;
60 if unsafe {
61 PeekNamedPipe(
62 stderr.as_raw_handle(),
63 null_mut(),
64 0,
65 null_mut(),
66 &mut bytes_available,
67 null_mut(),
68 )
69 } == 0
70 {
71 return Err(Error::new(
72 ErrorKind::IOError,
73 format!(
74 "PeekNamedPipe failed with {}",
75 std::io::Error::last_os_error()
76 ),
77 ));
78 }
79 }
80 #[cfg(unix)]
81 {
82 use std::os::unix::io::AsRawFd;
83 if unsafe { libc::ioctl(stderr.as_raw_fd(), libc::FIONREAD, &mut bytes_available) } != 0 {
84 return Err(Error::new(
85 ErrorKind::IOError,
86 format!("ioctl failed with {}", std::io::Error::last_os_error()),
87 ));
88 }
89 }
90 Ok(bytes_available.try_into().unwrap())
91}