1
- //! Windows asynchronous process handling.
1
+ //! Windows asynchronous process handling.ven
2
2
//!
3
3
//! Like with Unix we don't actually have a way of registering a process with an
4
4
//! IOCP object. As a result we similarly need another mechanism for getting a
15
15
//! `RegisterWaitForSingleObject` and then wait on the other end of the oneshot
16
16
//! from then on out.
17
17
18
- extern crate winapi;
19
- extern crate mio_named_pipes;
20
-
21
18
use std:: fmt;
22
- use std:: io;
19
+ use std:: future:: Future ;
20
+ use std:: io:: { self , Read , Write } ;
23
21
use std:: os:: windows:: prelude:: * ;
24
22
use std:: os:: windows:: process:: ExitStatusExt ;
25
- use std:: process:: { self , ExitStatus } ;
23
+ use std:: pin:: Pin ;
24
+ use std:: process;
26
25
use std:: ptr;
27
-
28
- use futures:: future:: Fuse ;
29
- use futures:: sync:: oneshot;
30
- use futures:: { Future , Poll , Async } ;
31
- use kill:: Kill ;
32
- use self :: mio_named_pipes:: NamedPipe ;
33
- use self :: winapi:: shared:: minwindef:: * ;
34
- use self :: winapi:: shared:: winerror:: * ;
35
- use self :: winapi:: um:: handleapi:: * ;
36
- use self :: winapi:: um:: processthreadsapi:: * ;
37
- use self :: winapi:: um:: synchapi:: * ;
38
- use self :: winapi:: um:: threadpoollegacyapiset:: * ;
39
- use self :: winapi:: um:: winbase:: * ;
40
- use self :: winapi:: um:: winnt:: * ;
41
- use super :: SpawnedChild ;
42
- use tokio_reactor:: { Handle , PollEvented } ;
26
+ use std:: task:: { Context , Poll } ;
27
+
28
+ use futures_channel:: oneshot:: { channel as oneshot, Receiver , Sender } ;
29
+ use futures_io:: { AsyncRead , AsyncWrite } ;
30
+ use mio_named_pipes:: NamedPipe ;
31
+ use winapi:: shared:: minwindef:: * ;
32
+ use winapi:: shared:: winerror:: * ;
33
+ use winapi:: um:: handleapi:: * ;
34
+ use winapi:: um:: processthreadsapi:: * ;
35
+ use winapi:: um:: synchapi:: * ;
36
+ use winapi:: um:: threadpoollegacyapiset:: * ;
37
+ use winapi:: um:: winbase:: * ;
38
+ use winapi:: um:: winnt:: * ;
39
+
40
+ use crate :: net:: driver:: Watcher ;
41
+ use crate :: process:: {
42
+ kill:: { ChildDropGuard , Kill } ,
43
+ Child as SpawnedChild , ChildStderr as SpawnedChildStderr , ChildStdin as SpawnedChildStdin ,
44
+ ChildStdout as SpawnedChildStdout , ExitStatus ,
45
+ } ;
43
46
44
47
#[ must_use = "futures do nothing unless polled" ]
45
48
pub struct Child {
@@ -48,7 +51,7 @@ pub struct Child {
48
51
}
49
52
50
53
impl fmt:: Debug for Child {
51
- fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
54
+ fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
52
55
fmt. debug_struct ( "Child" )
53
56
. field ( "pid" , & self . id ( ) )
54
57
. field ( "child" , & self . child )
@@ -58,28 +61,28 @@ impl fmt::Debug for Child {
58
61
}
59
62
60
63
struct Waiting {
61
- rx : Fuse < oneshot :: Receiver < ( ) > > ,
64
+ rx : Receiver < ( ) > ,
62
65
wait_object : HANDLE ,
63
- tx : * mut Option < oneshot :: Sender < ( ) > > ,
66
+ tx : * mut Option < Sender < ( ) > > ,
64
67
}
65
68
66
69
unsafe impl Sync for Waiting { }
67
70
unsafe impl Send for Waiting { }
68
71
69
- pub ( crate ) fn spawn_child ( cmd : & mut process:: Command , handle : & Handle ) -> io:: Result < SpawnedChild > {
72
+ pub ( crate ) fn spawn_child ( cmd : & mut process:: Command ) -> io:: Result < SpawnedChild > {
70
73
let mut child = cmd. spawn ( ) ?;
71
- let stdin = stdio ( child. stdin . take ( ) , handle ) ?;
72
- let stdout = stdio ( child. stdout . take ( ) , handle ) ?;
73
- let stderr = stdio ( child. stderr . take ( ) , handle ) ?;
74
+ let stdin = stdio ( child. stdin . take ( ) ) ?;
75
+ let stdout = stdio ( child. stdout . take ( ) ) ?;
76
+ let stderr = stdio ( child. stderr . take ( ) ) ?;
74
77
75
78
Ok ( SpawnedChild {
76
- child : Child {
79
+ child : ChildDropGuard :: new ( Child {
77
80
child,
78
81
waiting : None ,
79
- } ,
80
- stdin,
81
- stdout,
82
- stderr,
82
+ } ) ,
83
+ stdin : stdin . map ( |stdin| SpawnedChildStdin { inner : stdin } ) ,
84
+ stdout : stdout . map ( |stdout| SpawnedChildStdout { inner : stdout } ) ,
85
+ stderr : stderr . map ( |stderr| SpawnedChildStderr { inner : stderr } ) ,
83
86
} )
84
87
}
85
88
@@ -96,42 +99,47 @@ impl Kill for Child {
96
99
}
97
100
98
101
impl Future for Child {
99
- type Item = ExitStatus ;
100
- type Error = io:: Error ;
102
+ type Output = io:: Result < ExitStatus > ;
101
103
102
- fn poll ( & mut self ) -> Poll < Self :: Item , Self :: Error > {
104
+ fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < < Self as Future > :: Output > {
103
105
loop {
104
106
if let Some ( ref mut w) = self . waiting {
105
- match w. rx . poll ( ) . expect ( "should not be canceled" ) {
106
- Async :: Ready ( ( ) ) => { }
107
- Async :: NotReady => return Ok ( Async :: NotReady ) ,
107
+ match Pin :: new ( & mut w. rx ) . poll ( cx) {
108
+ Poll :: Ready ( Ok ( ( ) ) ) => { }
109
+ Poll :: Ready ( Err ( _) ) => panic ! ( "cancellation was not supposed to happen" ) ,
110
+ Poll :: Pending => return Poll :: Pending ,
108
111
}
109
- let status = try!( try_wait ( & self . child ) ) . expect ( "not ready yet" ) ;
110
- return Ok ( status. into ( ) )
112
+ return match try_wait ( & self . child ) {
113
+ Ok ( status) => Poll :: Ready ( Ok ( status. expect ( "not ready yet" ) ) ) ,
114
+ Err ( err) => Poll :: Ready ( Err ( err) ) ,
115
+ } ;
111
116
}
112
117
113
- if let Some ( e) = try!( try_wait ( & self . child ) ) {
114
- return Ok ( e. into ( ) )
118
+ match try_wait ( & self . child ) {
119
+ Ok ( Some ( e) ) => return Poll :: Ready ( Ok ( e) ) ,
120
+ Ok ( None ) => { }
121
+ Err ( err) => return Poll :: Ready ( Err ( err) ) ,
115
122
}
116
- let ( tx, rx) = oneshot:: channel ( ) ;
123
+ let ( tx, rx) = oneshot ( ) ;
117
124
let ptr = Box :: into_raw ( Box :: new ( Some ( tx) ) ) ;
118
125
let mut wait_object = ptr:: null_mut ( ) ;
119
126
let rc = unsafe {
120
- RegisterWaitForSingleObject ( & mut wait_object,
121
- self . child . as_raw_handle ( ) ,
122
- Some ( callback) ,
123
- ptr as * mut _ ,
124
- INFINITE ,
125
- WT_EXECUTEINWAITTHREAD |
126
- WT_EXECUTEONLYONCE )
127
+ RegisterWaitForSingleObject (
128
+ & mut wait_object,
129
+ self . child . as_raw_handle ( ) ,
130
+ Some ( callback) ,
131
+ ptr as * mut _ ,
132
+ INFINITE ,
133
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ,
134
+ )
127
135
} ;
128
136
if rc == 0 {
129
137
let err = io:: Error :: last_os_error ( ) ;
130
138
drop ( unsafe { Box :: from_raw ( ptr) } ) ;
131
- return Err ( err)
139
+ return Poll :: Ready ( Err ( err) ) ;
132
140
}
133
141
self . waiting = Some ( Waiting {
134
- rx : rx . fuse ( ) ,
142
+ rx,
135
143
wait_object,
136
144
tx : ptr,
137
145
} ) ;
@@ -151,9 +159,8 @@ impl Drop for Waiting {
151
159
}
152
160
}
153
161
154
- unsafe extern "system" fn callback ( ptr : PVOID ,
155
- _timer_fired : BOOLEAN ) {
156
- let complete = & mut * ( ptr as * mut Option < oneshot:: Sender < ( ) > > ) ;
162
+ unsafe extern "system" fn callback ( ptr : PVOID , _timer_fired : BOOLEAN ) {
163
+ let complete = & mut * ( ptr as * mut Option < Sender < ( ) > > ) ;
157
164
let _ = complete. take ( ) . unwrap ( ) . send ( ( ) ) ;
158
165
}
159
166
@@ -174,19 +181,57 @@ pub fn try_wait(child: &process::Child) -> io::Result<Option<ExitStatus>> {
174
181
}
175
182
}
176
183
177
- pub type ChildStdin = PollEvented < NamedPipe > ;
178
- pub type ChildStdout = PollEvented < NamedPipe > ;
179
- pub type ChildStderr = PollEvented < NamedPipe > ;
184
+ impl AsyncWrite for SpawnedChildStdin {
185
+ fn poll_write (
186
+ mut self : Pin < & mut Self > ,
187
+ cx : & mut Context < ' _ > ,
188
+ buf : & [ u8 ] ,
189
+ ) -> Poll < io:: Result < usize > > {
190
+ self . inner . poll_write_with_mut ( cx, |inner| inner. write ( buf) )
191
+ }
192
+
193
+ fn poll_flush ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
194
+ self . inner . poll_write_with_mut ( cx, |inner| inner. flush ( ) )
195
+ }
196
+
197
+ fn poll_close ( self : Pin < & mut Self > , _: & mut Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
198
+ Poll :: Ready ( Ok ( ( ) ) )
199
+ }
200
+ }
201
+
202
+ impl AsyncRead for SpawnedChildStdout {
203
+ fn poll_read (
204
+ mut self : Pin < & mut Self > ,
205
+ cx : & mut Context < ' _ > ,
206
+ buf : & mut [ u8 ] ,
207
+ ) -> Poll < io:: Result < usize > > {
208
+ self . inner . poll_read_with_mut ( cx, |inner| inner. read ( buf) )
209
+ }
210
+ }
211
+
212
+ impl AsyncRead for SpawnedChildStderr {
213
+ fn poll_read (
214
+ mut self : Pin < & mut Self > ,
215
+ cx : & mut Context < ' _ > ,
216
+ buf : & mut [ u8 ] ,
217
+ ) -> Poll < io:: Result < usize > > {
218
+ self . inner . poll_read_with_mut ( cx, |inner| inner. read ( buf) )
219
+ }
220
+ }
221
+
222
+ pub type ChildStdin = Watcher < NamedPipe > ;
223
+ pub type ChildStdout = Watcher < NamedPipe > ;
224
+ pub type ChildStderr = Watcher < NamedPipe > ;
180
225
181
- fn stdio < T > ( option : Option < T > , handle : & Handle )
182
- -> io :: Result < Option < PollEvented < NamedPipe > > >
183
- where T : IntoRawHandle ,
226
+ fn stdio < T > ( option : Option < T > ) -> io :: Result < Option < Watcher < NamedPipe > > >
227
+ where
228
+ T : IntoRawHandle ,
184
229
{
185
230
let io = match option {
186
231
Some ( io) => io,
187
232
None => return Ok ( None ) ,
188
233
} ;
189
234
let pipe = unsafe { NamedPipe :: from_raw_handle ( io. into_raw_handle ( ) ) } ;
190
- let io = try! ( PollEvented :: new_with_handle ( pipe, handle ) ) ;
235
+ let io = Watcher :: new ( pipe) ;
191
236
Ok ( Some ( io) )
192
237
}
0 commit comments