]>
Commit | Line | Data |
---|---|---|
abe05a73 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | // FIXME: This is a complete copy of `cargo/src/cargo/util/read2.rs` | |
12 | // Consider unify the read2() in libstd, cargo and this to prevent further code duplication. | |
13 | ||
14 | pub use self::imp::read2; | |
15 | ||
16 | #[cfg(not(any(unix, windows)))] | |
17 | mod imp { | |
18 | use std::io::{self, Read}; | |
94b46f34 | 19 | use std::process::{ChildStderr, ChildStdout}; |
abe05a73 | 20 | |
94b46f34 XL |
21 | pub fn read2( |
22 | out_pipe: ChildStdout, | |
23 | err_pipe: ChildStderr, | |
24 | data: &mut FnMut(bool, &mut Vec<u8>, bool), | |
25 | ) -> io::Result<()> { | |
abe05a73 XL |
26 | let mut buffer = Vec::new(); |
27 | out_pipe.read_to_end(&mut buffer)?; | |
28 | data(true, &mut buffer, true); | |
29 | buffer.clear(); | |
30 | err_pipe.read_to_end(&mut buffer)?; | |
31 | data(false, &mut buffer, true); | |
32 | Ok(()) | |
33 | } | |
34 | } | |
35 | ||
36 | #[cfg(unix)] | |
37 | mod imp { | |
94b46f34 | 38 | use libc; |
abe05a73 | 39 | use std::io; |
94b46f34 | 40 | use std::io::prelude::*; |
abe05a73 XL |
41 | use std::mem; |
42 | use std::os::unix::prelude::*; | |
94b46f34 | 43 | use std::process::{ChildStderr, ChildStdout}; |
abe05a73 | 44 | |
94b46f34 XL |
45 | pub fn read2( |
46 | mut out_pipe: ChildStdout, | |
47 | mut err_pipe: ChildStderr, | |
48 | data: &mut FnMut(bool, &mut Vec<u8>, bool), | |
49 | ) -> io::Result<()> { | |
abe05a73 XL |
50 | unsafe { |
51 | libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); | |
52 | libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); | |
53 | } | |
54 | ||
55 | let mut out_done = false; | |
56 | let mut err_done = false; | |
57 | let mut out = Vec::new(); | |
58 | let mut err = Vec::new(); | |
59 | ||
60 | let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; | |
61 | fds[0].fd = out_pipe.as_raw_fd(); | |
62 | fds[0].events = libc::POLLIN; | |
63 | fds[1].fd = err_pipe.as_raw_fd(); | |
64 | fds[1].events = libc::POLLIN; | |
0531ce1d XL |
65 | let mut nfds = 2; |
66 | let mut errfd = 1; | |
67 | ||
68 | while nfds > 0 { | |
abe05a73 | 69 | // wait for either pipe to become readable using `select` |
0531ce1d | 70 | let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; |
abe05a73 XL |
71 | if r == -1 { |
72 | let err = io::Error::last_os_error(); | |
73 | if err.kind() == io::ErrorKind::Interrupted { | |
94b46f34 | 74 | continue; |
abe05a73 | 75 | } |
94b46f34 | 76 | return Err(err); |
abe05a73 XL |
77 | } |
78 | ||
79 | // Read as much as we can from each pipe, ignoring EWOULDBLOCK or | |
80 | // EAGAIN. If we hit EOF, then this will happen because the underlying | |
81 | // reader will return Ok(0), in which case we'll see `Ok` ourselves. In | |
82 | // this case we flip the other fd back into blocking mode and read | |
83 | // whatever's leftover on that file descriptor. | |
94b46f34 XL |
84 | let handle = |res: io::Result<_>| match res { |
85 | Ok(_) => Ok(true), | |
86 | Err(e) => { | |
87 | if e.kind() == io::ErrorKind::WouldBlock { | |
88 | Ok(false) | |
89 | } else { | |
90 | Err(e) | |
abe05a73 XL |
91 | } |
92 | } | |
93 | }; | |
0531ce1d | 94 | if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { |
abe05a73 | 95 | err_done = true; |
0531ce1d | 96 | nfds -= 1; |
abe05a73 XL |
97 | } |
98 | data(false, &mut err, err_done); | |
0531ce1d XL |
99 | if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { |
100 | out_done = true; | |
101 | fds[0].fd = err_pipe.as_raw_fd(); | |
102 | errfd = 0; | |
103 | nfds -= 1; | |
abe05a73 | 104 | } |
0531ce1d | 105 | data(true, &mut out, out_done); |
abe05a73 | 106 | } |
0531ce1d | 107 | Ok(()) |
abe05a73 XL |
108 | } |
109 | } | |
110 | ||
111 | #[cfg(windows)] | |
112 | mod imp { | |
113 | extern crate miow; | |
114 | extern crate winapi; | |
115 | ||
116 | use std::io; | |
117 | use std::os::windows::prelude::*; | |
94b46f34 | 118 | use std::process::{ChildStderr, ChildStdout}; |
abe05a73 XL |
119 | use std::slice; |
120 | ||
121 | use self::miow::iocp::{CompletionPort, CompletionStatus}; | |
122 | use self::miow::pipe::NamedPipe; | |
123 | use self::miow::Overlapped; | |
0531ce1d | 124 | use self::winapi::shared::winerror::ERROR_BROKEN_PIPE; |
abe05a73 XL |
125 | |
126 | struct Pipe<'a> { | |
127 | dst: &'a mut Vec<u8>, | |
128 | overlapped: Overlapped, | |
129 | pipe: NamedPipe, | |
130 | done: bool, | |
131 | } | |
132 | ||
94b46f34 XL |
133 | pub fn read2( |
134 | out_pipe: ChildStdout, | |
135 | err_pipe: ChildStderr, | |
136 | data: &mut FnMut(bool, &mut Vec<u8>, bool), | |
137 | ) -> io::Result<()> { | |
abe05a73 XL |
138 | let mut out = Vec::new(); |
139 | let mut err = Vec::new(); | |
140 | ||
141 | let port = CompletionPort::new(1)?; | |
142 | port.add_handle(0, &out_pipe)?; | |
143 | port.add_handle(1, &err_pipe)?; | |
144 | ||
145 | unsafe { | |
146 | let mut out_pipe = Pipe::new(out_pipe, &mut out); | |
147 | let mut err_pipe = Pipe::new(err_pipe, &mut err); | |
148 | ||
149 | out_pipe.read()?; | |
150 | err_pipe.read()?; | |
151 | ||
152 | let mut status = [CompletionStatus::zero(), CompletionStatus::zero()]; | |
153 | ||
154 | while !out_pipe.done || !err_pipe.done { | |
155 | for status in port.get_many(&mut status, None)? { | |
156 | if status.token() == 0 { | |
157 | out_pipe.complete(status); | |
158 | data(true, out_pipe.dst, out_pipe.done); | |
159 | out_pipe.read()?; | |
160 | } else { | |
161 | err_pipe.complete(status); | |
162 | data(false, err_pipe.dst, err_pipe.done); | |
163 | err_pipe.read()?; | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | Ok(()) | |
169 | } | |
170 | } | |
171 | ||
172 | impl<'a> Pipe<'a> { | |
173 | unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> { | |
174 | Pipe { | |
175 | dst: dst, | |
176 | pipe: NamedPipe::from_raw_handle(p.into_raw_handle()), | |
177 | overlapped: Overlapped::zero(), | |
178 | done: false, | |
179 | } | |
180 | } | |
181 | ||
182 | unsafe fn read(&mut self) -> io::Result<()> { | |
183 | let dst = slice_to_end(self.dst); | |
184 | match self.pipe.read_overlapped(dst, self.overlapped.raw()) { | |
185 | Ok(_) => Ok(()), | |
186 | Err(e) => { | |
187 | if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { | |
188 | self.done = true; | |
189 | Ok(()) | |
190 | } else { | |
191 | Err(e) | |
192 | } | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | unsafe fn complete(&mut self, status: &CompletionStatus) { | |
198 | let prev = self.dst.len(); | |
199 | self.dst.set_len(prev + status.bytes_transferred() as usize); | |
200 | if status.bytes_transferred() == 0 { | |
201 | self.done = true; | |
202 | } | |
203 | } | |
204 | } | |
205 | ||
206 | unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] { | |
207 | if v.capacity() == 0 { | |
208 | v.reserve(16); | |
209 | } | |
210 | if v.capacity() == v.len() { | |
211 | v.reserve(1); | |
212 | } | |
94b46f34 XL |
213 | slice::from_raw_parts_mut( |
214 | v.as_mut_ptr().offset(v.len() as isize), | |
215 | v.capacity() - v.len(), | |
216 | ) | |
abe05a73 XL |
217 | } |
218 | } |