1 // FIXME: This is a complete copy of `cargo/src/cargo/util/read2.rs`
2 // Consider unify the read2() in libstd, cargo and this to prevent further code duplication.
4 pub use self::imp::read2;
6 #[cfg(not(any(unix, windows)))]
8 use std::io::{self, Read};
9 use std::process::{ChildStderr, ChildStdout};
12 out_pipe: ChildStdout,
13 err_pipe: ChildStderr,
14 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
16 let mut buffer = Vec::new();
17 out_pipe.read_to_end(&mut buffer)?;
18 data(true, &mut buffer, true);
20 err_pipe.read_to_end(&mut buffer)?;
21 data(false, &mut buffer, true);
29 use std::io::prelude::*;
31 use std::os::unix::prelude::*;
32 use std::process::{ChildStderr, ChildStdout};
35 mut out_pipe: ChildStdout,
36 mut err_pipe: ChildStderr,
37 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
40 libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
41 libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
44 let mut out_done = false;
45 let mut err_done = false;
46 let mut out = Vec::new();
47 let mut err = Vec::new();
49 let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
50 fds[0].fd = out_pipe.as_raw_fd();
51 fds[0].events = libc::POLLIN;
52 fds[1].fd = err_pipe.as_raw_fd();
53 fds[1].events = libc::POLLIN;
58 // wait for either pipe to become readable using `select`
59 let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
61 let err = io::Error::last_os_error();
62 if err.kind() == io::ErrorKind::Interrupted {
68 // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
69 // EAGAIN. If we hit EOF, then this will happen because the underlying
70 // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
71 // this case we flip the other fd back into blocking mode and read
72 // whatever's leftover on that file descriptor.
73 let handle = |res: io::Result<_>| match res {
76 if e.kind() == io::ErrorKind::WouldBlock {
83 if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
87 data(false, &mut err, err_done);
88 if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
90 fds[0].fd = err_pipe.as_raw_fd();
94 data(true, &mut out, out_done);
103 use std::os::windows::prelude::*;
104 use std::process::{ChildStderr, ChildStdout};
107 use miow::iocp::{CompletionPort, CompletionStatus};
108 use miow::pipe::NamedPipe;
109 use miow::Overlapped;
110 use winapi::shared::winerror::ERROR_BROKEN_PIPE;
113 dst: &'a mut Vec<u8>,
114 overlapped: Overlapped,
120 out_pipe: ChildStdout,
121 err_pipe: ChildStderr,
122 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
123 ) -> io::Result<()> {
124 let mut out = Vec::new();
125 let mut err = Vec::new();
127 let port = CompletionPort::new(1)?;
128 port.add_handle(0, &out_pipe)?;
129 port.add_handle(1, &err_pipe)?;
132 let mut out_pipe = Pipe::new(out_pipe, &mut out);
133 let mut err_pipe = Pipe::new(err_pipe, &mut err);
138 let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];
140 while !out_pipe.done || !err_pipe.done {
141 for status in port.get_many(&mut status, None)? {
142 if status.token() == 0 {
143 out_pipe.complete(status);
144 data(true, out_pipe.dst, out_pipe.done);
147 err_pipe.complete(status);
148 data(false, err_pipe.dst, err_pipe.done);
159 unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
162 pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
163 overlapped: Overlapped::zero(),
168 unsafe fn read(&mut self) -> io::Result<()> {
169 let dst = slice_to_end(self.dst);
170 match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
173 if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
183 unsafe fn complete(&mut self, status: &CompletionStatus) {
184 let prev = self.dst.len();
185 self.dst.set_len(prev + status.bytes_transferred() as usize);
186 if status.bytes_transferred() == 0 {
192 unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
193 if v.capacity() == 0 {
196 if v.capacity() == v.len() {
199 slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), v.capacity() - v.len())