1pub use self::imp::read2;
2
3#[cfg(unix)]
4mod imp {
5 use libc::{c_int, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
6 use std::io;
7 use std::io::prelude::*;
8 use std::mem;
9 use std::os::unix::prelude::*;
10 use std::process::{ChildStderr, ChildStdout};
11
12 fn set_nonblock(fd: c_int) -> io::Result<()> {
13 let flags = unsafe { fcntl(fd, F_GETFL) };
14 if flags == -1 || unsafe { fcntl(fd, F_SETFL, flags | O_NONBLOCK) } == -1 {
15 return Err(io::Error::last_os_error());
16 }
17 Ok(())
18 }
19
20 pub fn read2(
21 mut out_pipe: ChildStdout,
22 mut err_pipe: ChildStderr,
23 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
24 ) -> io::Result<()> {
25 set_nonblock(out_pipe.as_raw_fd())?;
26 set_nonblock(err_pipe.as_raw_fd())?;
27
28 let mut out_done = false;
29 let mut err_done = false;
30 let mut out = Vec::new();
31 let mut err = Vec::new();
32
33 let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
34 fds[0].fd = out_pipe.as_raw_fd();
35 fds[0].events = libc::POLLIN;
36 fds[1].fd = err_pipe.as_raw_fd();
37 fds[1].events = libc::POLLIN;
38 let mut nfds = 2;
39 let mut errfd = 1;
40
41 while nfds > 0 {
42 let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
44 if r == -1 {
45 let err = io::Error::last_os_error();
46 if err.kind() == io::ErrorKind::Interrupted {
47 continue;
48 }
49 return Err(err);
50 }
51
52 let handle = |res: io::Result<_>| match res {
58 Ok(_) => Ok(true),
59 Err(e) => {
60 if e.kind() == io::ErrorKind::WouldBlock {
61 Ok(false)
62 } else {
63 Err(e)
64 }
65 }
66 };
67 if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
68 err_done = true;
69 nfds -= 1;
70 }
71 data(false, &mut err, err_done);
72 if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
73 out_done = true;
74 fds[0].fd = err_pipe.as_raw_fd();
75 errfd = 0;
76 nfds -= 1;
77 }
78 data(true, &mut out, out_done);
79 }
80 Ok(())
81 }
82}
83
84#[cfg(windows)]
85mod imp {
86 use std::io;
87 use std::os::windows::prelude::*;
88 use std::process::{ChildStderr, ChildStdout};
89 use std::slice;
90
91 use miow::iocp::{CompletionPort, CompletionStatus};
92 use miow::pipe::NamedPipe;
93 use miow::Overlapped;
94 use windows_sys::Win32::Foundation::ERROR_BROKEN_PIPE;
95
96 struct Pipe<'a> {
97 dst: &'a mut Vec<u8>,
98 overlapped: Overlapped,
99 pipe: NamedPipe,
100 done: bool,
101 }
102
103 pub fn read2(
104 out_pipe: ChildStdout,
105 err_pipe: ChildStderr,
106 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
107 ) -> io::Result<()> {
108 let mut out = Vec::new();
109 let mut err = Vec::new();
110
111 let port = CompletionPort::new(1)?;
112 port.add_handle(0, &out_pipe)?;
113 port.add_handle(1, &err_pipe)?;
114
115 unsafe {
116 let mut out_pipe = Pipe::new(out_pipe, &mut out);
117 let mut err_pipe = Pipe::new(err_pipe, &mut err);
118
119 out_pipe.read()?;
120 err_pipe.read()?;
121
122 let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];
123
124 while !out_pipe.done || !err_pipe.done {
125 for status in port.get_many(&mut status, None)? {
126 if status.token() == 0 {
127 out_pipe.complete(status);
128 data(true, out_pipe.dst, out_pipe.done);
129 out_pipe.read()?;
130 } else {
131 err_pipe.complete(status);
132 data(false, err_pipe.dst, err_pipe.done);
133 err_pipe.read()?;
134 }
135 }
136 }
137
138 Ok(())
139 }
140 }
141
142 impl<'a> Pipe<'a> {
143 unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
144 Pipe {
145 dst,
146 pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
147 overlapped: Overlapped::zero(),
148 done: false,
149 }
150 }
151
152 unsafe fn read(&mut self) -> io::Result<()> {
153 let dst = slice_to_end(self.dst);
154 match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
155 Ok(_) => Ok(()),
156 Err(e) => {
157 if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
158 self.done = true;
159 Ok(())
160 } else {
161 Err(e)
162 }
163 }
164 }
165 }
166
167 unsafe fn complete(&mut self, status: &CompletionStatus) {
168 let prev = self.dst.len();
169 self.dst.set_len(prev + status.bytes_transferred() as usize);
170 if status.bytes_transferred() == 0 {
171 self.done = true;
172 }
173 }
174 }
175
176 unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
177 if v.capacity() == 0 {
178 v.reserve(16);
179 }
180 if v.capacity() == v.len() {
181 v.reserve(1);
182 }
183 slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len())
184 }
185}