summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cc/src/parallel/stderr.rs
blob: 47fa085dba430a9010eaa924699680d1200e53c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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())
}