1
1
// This is copied from
2
2
// https://github.com/rust-lang/rust/blob/master/src/tools/compiletest/src/read2.rs
3
3
// and falls under the MIT or Apache 2.0 licenses.
4
+ pub use self :: imp:: read2;
4
5
5
- use std:: io;
6
- use std:: io:: prelude:: * ;
7
- use std:: mem;
8
- use std:: os:: unix:: prelude:: * ;
9
- use std:: process:: { ChildStderr , ChildStdout } ;
10
-
11
- pub fn read2 (
12
- mut out_pipe : ChildStdout ,
13
- mut err_pipe : ChildStderr ,
14
- data : & mut dyn FnMut ( bool , & mut Vec < u8 > , bool ) ,
15
- ) -> io:: Result < ( ) > {
16
- unsafe {
17
- libc:: fcntl ( out_pipe. as_raw_fd ( ) , libc:: F_SETFL , libc:: O_NONBLOCK ) ;
18
- libc:: fcntl ( err_pipe. as_raw_fd ( ) , libc:: F_SETFL , libc:: O_NONBLOCK ) ;
6
+ #[ cfg( not( any( unix, windows) ) ) ]
7
+ mod imp {
8
+ use std:: io:: { self , Read } ;
9
+ use std:: process:: { ChildStderr , ChildStdout } ;
10
+
11
+ pub fn read2 (
12
+ out_pipe : ChildStdout ,
13
+ err_pipe : ChildStderr ,
14
+ data : & mut dyn FnMut ( bool , & mut Vec < u8 > , bool ) ,
15
+ ) -> io:: Result < ( ) > {
16
+ let mut buffer = Vec :: new ( ) ;
17
+ out_pipe. read_to_end ( & mut buffer) ?;
18
+ data ( true , & mut buffer, true ) ;
19
+ buffer. clear ( ) ;
20
+ err_pipe. read_to_end ( & mut buffer) ?;
21
+ data ( false , & mut buffer, true ) ;
22
+ Ok ( ( ) )
19
23
}
24
+ }
25
+
26
+ #[ cfg( unix) ]
27
+ mod imp {
28
+ use std:: io;
29
+ use std:: io:: prelude:: * ;
30
+ use std:: mem;
31
+ use std:: os:: unix:: prelude:: * ;
32
+ use std:: process:: { ChildStderr , ChildStdout } ;
33
+
34
+ pub fn read2 (
35
+ mut out_pipe : ChildStdout ,
36
+ mut err_pipe : ChildStderr ,
37
+ data : & mut dyn FnMut ( bool , & mut Vec < u8 > , bool ) ,
38
+ ) -> io:: Result < ( ) > {
39
+ unsafe {
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 ) ;
42
+ }
43
+
44
+ let mut out_done = false ;
45
+ let mut err_done = false ;
46
+ let mut out = Vec :: new ( ) ;
47
+ let mut err = Vec :: new ( ) ;
48
+
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 ;
54
+ let mut nfds = 2 ;
55
+ let mut errfd = 1 ;
56
+
57
+ while nfds > 0 {
58
+ // wait for either pipe to become readable using `select`
59
+ let r = unsafe { libc:: poll ( fds. as_mut_ptr ( ) , nfds, -1 ) } ;
60
+ if r == -1 {
61
+ let err = io:: Error :: last_os_error ( ) ;
62
+ if err. kind ( ) == io:: ErrorKind :: Interrupted {
63
+ continue ;
64
+ }
65
+ return Err ( err) ;
66
+ }
20
67
21
- let mut out_done = false ;
22
- let mut err_done = false ;
23
- let mut out = Vec :: new ( ) ;
24
- let mut err = Vec :: new ( ) ;
25
-
26
- let mut fds: [ libc:: pollfd ; 2 ] = unsafe { mem:: zeroed ( ) } ;
27
- fds[ 0 ] . fd = out_pipe. as_raw_fd ( ) ;
28
- fds[ 0 ] . events = libc:: POLLIN ;
29
- fds[ 1 ] . fd = err_pipe. as_raw_fd ( ) ;
30
- fds[ 1 ] . events = libc:: POLLIN ;
31
- let mut nfds = 2 ;
32
- let mut errfd = 1 ;
33
-
34
- while nfds > 0 {
35
- // wait for either pipe to become readable using `select`
36
- let r = unsafe { libc:: poll ( fds. as_mut_ptr ( ) , nfds, -1 ) } ;
37
- if r == -1 {
38
- let err = io:: Error :: last_os_error ( ) ;
39
- if err. kind ( ) == io:: ErrorKind :: Interrupted {
40
- continue ;
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 {
74
+ Ok ( _) => Ok ( true ) ,
75
+ Err ( e) => {
76
+ if e. kind ( ) == io:: ErrorKind :: WouldBlock {
77
+ Ok ( false )
78
+ } else {
79
+ Err ( e)
80
+ }
81
+ }
82
+ } ;
83
+ if !err_done && fds[ errfd] . revents != 0 && handle ( err_pipe. read_to_end ( & mut err) ) ? {
84
+ err_done = true ;
85
+ nfds -= 1 ;
86
+ }
87
+ data ( false , & mut err, err_done) ;
88
+ if !out_done && fds[ 0 ] . revents != 0 && handle ( out_pipe. read_to_end ( & mut out) ) ? {
89
+ out_done = true ;
90
+ fds[ 0 ] . fd = err_pipe. as_raw_fd ( ) ;
91
+ errfd = 0 ;
92
+ nfds -= 1 ;
41
93
}
42
- return Err ( err ) ;
94
+ data ( true , & mut out , out_done ) ;
43
95
}
96
+ Ok ( ( ) )
97
+ }
98
+ }
99
+
100
+ #[ cfg( windows) ]
101
+ mod imp {
102
+ use std:: io;
103
+ use std:: os:: windows:: prelude:: * ;
104
+ use std:: process:: { ChildStderr , ChildStdout } ;
105
+ use std:: slice;
106
+
107
+ use miow:: iocp:: { CompletionPort , CompletionStatus } ;
108
+ use miow:: pipe:: NamedPipe ;
109
+ use miow:: Overlapped ;
110
+ use winapi:: shared:: winerror:: ERROR_BROKEN_PIPE ;
111
+
112
+ struct Pipe < ' a > {
113
+ dst : & ' a mut Vec < u8 > ,
114
+ overlapped : Overlapped ,
115
+ pipe : NamedPipe ,
116
+ done : bool ,
117
+ }
118
+
119
+ pub fn read2 (
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 ( ) ;
126
+
127
+ let port = CompletionPort :: new ( 1 ) ?;
128
+ port. add_handle ( 0 , & out_pipe) ?;
129
+ port. add_handle ( 1 , & err_pipe) ?;
44
130
45
- // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
46
- // EAGAIN. If we hit EOF, then this will happen because the underlying
47
- // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
48
- // this case we flip the other fd back into blocking mode and read
49
- // whatever's leftover on that file descriptor.
50
- let handle = |res : io:: Result < _ > | match res {
51
- Ok ( _) => Ok ( true ) ,
52
- Err ( e) => {
53
- if e. kind ( ) == io:: ErrorKind :: WouldBlock {
54
- Ok ( false )
55
- } else {
56
- Err ( e)
131
+ unsafe {
132
+ let mut out_pipe = Pipe :: new ( out_pipe, & mut out) ;
133
+ let mut err_pipe = Pipe :: new ( err_pipe, & mut err) ;
134
+
135
+ out_pipe. read ( ) ?;
136
+ err_pipe. read ( ) ?;
137
+
138
+ let mut status = [ CompletionStatus :: zero ( ) , CompletionStatus :: zero ( ) ] ;
139
+
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 ) ;
145
+ out_pipe. read ( ) ?;
146
+ } else {
147
+ err_pipe. complete ( status) ;
148
+ data ( false , err_pipe. dst , err_pipe. done ) ;
149
+ err_pipe. read ( ) ?;
150
+ }
57
151
}
58
152
}
59
- } ;
60
- if !err_done && fds[ errfd] . revents != 0 && handle ( err_pipe. read_to_end ( & mut err) ) ? {
61
- err_done = true ;
62
- nfds -= 1 ;
153
+
154
+ Ok ( ( ) )
63
155
}
64
- data ( false , & mut err, err_done) ;
65
- if !out_done && fds[ 0 ] . revents != 0 && handle ( out_pipe. read_to_end ( & mut out) ) ? {
66
- out_done = true ;
67
- fds[ 0 ] . fd = err_pipe. as_raw_fd ( ) ;
68
- errfd = 0 ;
69
- nfds -= 1 ;
156
+ }
157
+
158
+ impl < ' a > Pipe < ' a > {
159
+ unsafe fn new < P : IntoRawHandle > ( p : P , dst : & ' a mut Vec < u8 > ) -> Pipe < ' a > {
160
+ Pipe {
161
+ dst : dst,
162
+ pipe : NamedPipe :: from_raw_handle ( p. into_raw_handle ( ) ) ,
163
+ overlapped : Overlapped :: zero ( ) ,
164
+ done : false ,
165
+ }
166
+ }
167
+
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 ( ) ) {
171
+ Ok ( _) => Ok ( ( ) ) ,
172
+ Err ( e) => {
173
+ if e. raw_os_error ( ) == Some ( ERROR_BROKEN_PIPE as i32 ) {
174
+ self . done = true ;
175
+ Ok ( ( ) )
176
+ } else {
177
+ Err ( e)
178
+ }
179
+ }
180
+ }
181
+ }
182
+
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 {
187
+ self . done = true ;
188
+ }
70
189
}
71
- data ( true , & mut out, out_done) ;
72
190
}
73
- Ok ( ( ) )
74
- }
191
+
192
+ unsafe fn slice_to_end ( v : & mut Vec < u8 > ) -> & mut [ u8 ] {
193
+ if v. capacity ( ) == 0 {
194
+ v. reserve ( 16 ) ;
195
+ }
196
+ if v. capacity ( ) == v. len ( ) {
197
+ v. reserve ( 1 ) ;
198
+ }
199
+ slice:: from_raw_parts_mut ( v. as_mut_ptr ( ) . offset ( v. len ( ) as isize ) , v. capacity ( ) - v. len ( ) )
200
+ }
201
+ }
0 commit comments