tokio_process/lib.rs
1//! An implementation of asynchronous process management for Tokio.
2//!
3//! > This crate has been **deprecated in tokio 0.2.x** and has been moved into
4//! > [`tokio::process`] behind the `process` [feature flag].
5//!
6//! [`tokio::process`]: https://docs.rs/tokio/latest/tokio/process/index.html
7//! [feature flag]: https://docs.rs/tokio/latest/tokio/index.html#feature-flags
8//!
9//! This crate provides a `CommandExt` trait to enhance the functionality of the
10//! `Command` type in the standard library. The three methods provided by this
11//! trait mirror the "spawning" methods in the standard library. The
12//! `CommandExt` trait in this crate, though, returns "future aware" types that
13//! interoperate with Tokio. The asynchronous process support is provided
14//! through signal handling on Unix and system APIs on Windows.
15//!
16//! # Examples
17//!
18//! Here's an example program which will spawn `echo hello world` and then wait
19//! for it using an event loop.
20//!
21//! ```no_run
22//! extern crate futures;
23//! extern crate tokio;
24//! extern crate tokio_process;
25//!
26//! use std::process::Command;
27//!
28//! use futures::Future;
29//! use tokio_process::CommandExt;
30//!
31//! fn main() {
32//! // Use the standard library's `Command` type to build a process and
33//! // then execute it via the `CommandExt` trait.
34//! let child = Command::new("echo").arg("hello").arg("world")
35//! .spawn_async();
36//!
37//! // Make sure our child succeeded in spawning and process the result
38//! let future = child.expect("failed to spawn")
39//! .map(|status| println!("exit status: {}", status))
40//! .map_err(|e| panic!("failed to wait for exit: {}", e));
41//!
42//! // Send the future to the tokio runtime for execution
43//! tokio::run(future)
44//! }
45//! ```
46//!
47//! Next, let's take a look at an example where we not only spawn `echo hello
48//! world` but we also capture its output.
49//!
50//! ```no_run
51//! extern crate futures;
52//! extern crate tokio;
53//! extern crate tokio_process;
54//!
55//! use std::process::Command;
56//!
57//! use futures::Future;
58//! use tokio_process::CommandExt;
59//!
60//! fn main() {
61//! // Like above, but use `output_async` which returns a future instead of
62//! // immediately returning the `Child`.
63//! let output = Command::new("echo").arg("hello").arg("world")
64//! .output_async();
65//!
66//! let future = output.map_err(|e| panic!("failed to collect output: {}", e))
67//! .map(|output| {
68//! assert!(output.status.success());
69//! assert_eq!(output.stdout, b"hello world\n");
70//! });
71//!
72//! tokio::run(future);
73//! }
74//! ```
75//!
76//! We can also read input line by line.
77//!
78//! ```no_run
79//! extern crate failure;
80//! extern crate futures;
81//! extern crate tokio;
82//! extern crate tokio_process;
83//! extern crate tokio_io;
84//!
85//! use failure::Error;
86//! use futures::{Future, Stream};
87//! use std::io::BufReader;
88//! use std::process::{Command, Stdio};
89//! use tokio_process::{Child, ChildStdout, CommandExt};
90//!
91//! fn lines_stream(child: &mut Child) -> impl Stream<Item = String, Error = Error> + Send + 'static {
92//! let stdout = child.stdout().take()
93//! .expect("child did not have a handle to stdout");
94//!
95//! tokio_io::io::lines(BufReader::new(stdout))
96//! // Convert any io::Error into a failure::Error for better flexibility
97//! .map_err(|e| Error::from(e))
98//! // We print each line we've received here as an example of a way we can
99//! // do something with the data. This can be changed to map the data to
100//! // something else, or to consume it differently.
101//! .inspect(|line| println!("Line: {}", line))
102//! }
103//!
104//! fn main() {
105//! // Lazily invoke any code so it can run directly within the tokio runtime
106//! tokio::run(futures::lazy(|| {
107//! let mut cmd = Command::new("cat");
108//!
109//! // Specify that we want the command's standard output piped back to us.
110//! // By default, standard input/output/error will be inherited from the
111//! // current process (for example, this means that standard input will
112//! // come from the keyboard and standard output/error will go directly to
113//! // the terminal if this process is invoked from the command line).
114//! cmd.stdout(Stdio::piped());
115//!
116//! let mut child = cmd.spawn_async()
117//! .expect("failed to spawn command");
118//!
119//! let lines = lines_stream(&mut child);
120//!
121//! // Spawning into the tokio runtime requires that the future's Item and
122//! // Error are both `()`. This is because tokio doesn't know what to do
123//! // with any results or errors, so it requires that we've handled them!
124//! //
125//! // We can replace these sample usages of the child's exit status (or
126//! // an encountered error) perform some different actions if needed!
127//! // For example, log the error, or send a message on a channel, etc.
128//! let child_future = child
129//! .map(|status| println!("child status was: {}", status))
130//! .map_err(|e| panic!("error while running child: {}", e));
131//!
132//! // Ensure the child process can live on within the runtime, otherwise
133//! // the process will get killed if this handle is dropped
134//! tokio::spawn(child_future);
135//!
136//! // Return a future to tokio. This is the same as calling using
137//! // `tokio::spawn` above, but without having to return a dummy future
138//! // here.
139//! lines
140//! // Convert the stream of values into a future which will resolve
141//! // once the entire stream has been consumed. In this example we
142//! // don't need to do anything with the data within the `for_each`
143//! // call, but you can extend this to do something else (keep in mind
144//! // that the stream will not produce items until the future returned
145//! // from the closure resolves).
146//! .for_each(|_| Ok(()))
147//! // Similarly we "handle" any errors that arise, as required by tokio.
148//! .map_err(|e| panic!("error while processing lines: {}", e))
149//! }));
150//! }
151//! ```
152//!
153//! # Caveats
154//!
155//! While similar to the standard library, this crate's `Child` type differs
156//! importantly in the behavior of `drop`. In the standard library, a child
157//! process will continue running after the instance of `std::process::Child`
158//! is dropped. In this crate, however, because `tokio_process::Child` is a
159//! future of the child's `ExitStatus`, a child process is terminated if
160//! `tokio_process::Child` is dropped. The behavior of the standard library can
161//! be regained with the `Child::forget` method.
162
163#![warn(missing_debug_implementations)]
164#![deny(missing_docs)]
165#![doc(html_root_url = "https://docs.rs/tokio-process/0.2")]
166
167extern crate futures;
168extern crate tokio_io;
169extern crate tokio_reactor;
170
171#[cfg(unix)]
172#[macro_use]
173extern crate lazy_static;
174#[cfg(unix)]
175#[macro_use]
176extern crate log;
177
178use std::io::{self, Read, Write};
179use std::process::{Command, ExitStatus, Output, Stdio};
180
181use crate::kill::Kill;
182use futures::future::{ok, Either};
183use futures::{Async, Future, IntoFuture, Poll};
184use std::fmt;
185use tokio_io::io::read_to_end;
186use tokio_io::{AsyncRead, AsyncWrite, IoFuture};
187use tokio_reactor::Handle;
188
189#[path = "unix/mod.rs"]
190#[cfg(unix)]
191mod imp;
192
193#[path = "windows.rs"]
194#[cfg(windows)]
195mod imp;
196
197mod kill;
198
199/// Extensions provided by this crate to the `Command` type in the standard
200/// library.
201///
202/// This crate primarily enhances the standard library's `Command` type with
203/// asynchronous capabilities. The currently three blocking functions in the
204/// standard library, `spawn`, `status`, and `output`, all have asynchronous
205/// versions through this trait.
206///
207/// Note that the `Child` type spawned is specific to this crate, and that the
208/// I/O handles created from this crate are all asynchronous as well (differing
209/// from their `std` counterparts).
210pub trait CommandExt {
211 /// Executes the command as a child process, returning a handle to it.
212 ///
213 /// By default, stdin, stdout and stderr are inherited from the parent.
214 ///
215 /// This method will spawn the child process synchronously and return a
216 /// handle to a future-aware child process. The `Child` returned implements
217 /// `Future` itself to acquire the `ExitStatus` of the child, and otherwise
218 /// the `Child` has methods to acquire handles to the stdin, stdout, and
219 /// stderr streams.
220 ///
221 /// All I/O this child does will be associated with the current default
222 /// event loop.
223 fn spawn_async(&mut self) -> io::Result<Child> {
224 self.spawn_async_with_handle(&Handle::default())
225 }
226
227 /// Executes the command as a child process, returning a handle to it.
228 ///
229 /// By default, stdin, stdout and stderr are inherited from the parent.
230 ///
231 /// This method will spawn the child process synchronously and return a
232 /// handle to a future-aware child process. The `Child` returned implements
233 /// `Future` itself to acquire the `ExitStatus` of the child, and otherwise
234 /// the `Child` has methods to acquire handles to the stdin, stdout, and
235 /// stderr streams.
236 ///
237 /// The `handle` specified to this method must be a handle to a valid event
238 /// loop, and all I/O this child does will be associated with the specified
239 /// event loop.
240 fn spawn_async_with_handle(&mut self, handle: &Handle) -> io::Result<Child>;
241
242 /// Executes a command as a child process, waiting for it to finish and
243 /// collecting its exit status.
244 ///
245 /// By default, stdin, stdout and stderr are inherited from the parent.
246 ///
247 /// The `StatusAsync` future returned will resolve to the `ExitStatus`
248 /// type in the standard library representing how the process exited. If
249 /// any input/output handles are set to a pipe then they will be immediately
250 /// closed after the child is spawned.
251 ///
252 /// All I/O this child does will be associated with the current default
253 /// event loop.
254 ///
255 /// If the `StatusAsync` future is dropped before the future resolves, then
256 /// the child will be killed, if it was spawned.
257 ///
258 /// # Errors
259 ///
260 /// This function will return an error immediately if the child process
261 /// cannot be spawned. Otherwise errors obtained while waiting for the child
262 /// are returned through the `StatusAsync` future.
263 fn status_async(&mut self) -> io::Result<StatusAsync> {
264 self.status_async_with_handle(&Handle::default())
265 }
266
267 /// Executes a command as a child process, waiting for it to finish and
268 /// collecting its exit status.
269 ///
270 /// By default, stdin, stdout and stderr are inherited from the parent.
271 ///
272 /// The `StatusAsync` future returned will resolve to the `ExitStatus`
273 /// type in the standard library representing how the process exited. If
274 /// any input/output handles are set to a pipe then they will be immediately
275 /// closed after the child is spawned.
276 ///
277 /// The `handle` specified must be a handle to a valid event loop, and all
278 /// I/O this child does will be associated with the specified event loop.
279 ///
280 /// If the `StatusAsync` future is dropped before the future resolves, then
281 /// the child will be killed, if it was spawned.
282 ///
283 /// # Errors
284 ///
285 /// This function will return an error immediately if the child process
286 /// cannot be spawned. Otherwise errors obtained while waiting for the child
287 /// are returned through the `StatusAsync` future.
288 fn status_async_with_handle(&mut self, handle: &Handle) -> io::Result<StatusAsync>;
289
290 /// Executes the command as a child process, waiting for it to finish and
291 /// collecting all of its output.
292 ///
293 /// > **Note**: this method, unlike the standard library, will
294 /// > unconditionally configure the stdout/stderr handles to be pipes, even
295 /// > if they have been previously configured. If this is not desired then
296 /// > the `spawn_async` method should be used in combination with the
297 /// > `wait_with_output` method on child.
298 ///
299 /// This method will return a future representing the collection of the
300 /// child process's stdout/stderr. The `OutputAsync` future will resolve to
301 /// the `Output` type in the standard library, containing `stdout` and
302 /// `stderr` as `Vec<u8>` along with an `ExitStatus` representing how the
303 /// process exited.
304 ///
305 /// All I/O this child does will be associated with the current default
306 /// event loop.
307 ///
308 /// If the `OutputAsync` future is dropped before the future resolves, then
309 /// the child will be killed, if it was spawned.
310 fn output_async(&mut self) -> OutputAsync {
311 self.output_async_with_handle(&Handle::default())
312 }
313
314 /// Executes the command as a child process, waiting for it to finish and
315 /// collecting all of its output.
316 ///
317 /// > **Note**: this method, unlike the standard library, will
318 /// > unconditionally configure the stdout/stderr handles to be pipes, even
319 /// > if they have been previously configured. If this is not desired then
320 /// > the `spawn_async` method should be used in combination with the
321 /// > `wait_with_output` method on child.
322 ///
323 /// This method will return a future representing the collection of the
324 /// child process's stdout/stderr. The `OutputAsync` future will resolve to
325 /// the `Output` type in the standard library, containing `stdout` and
326 /// `stderr` as `Vec<u8>` along with an `ExitStatus` representing how the
327 /// process exited.
328 ///
329 /// The `handle` specified must be a handle to a valid event loop, and all
330 /// I/O this child does will be associated with the specified event loop.
331 ///
332 /// If the `OutputAsync` future is dropped before the future resolves, then
333 /// the child will be killed, if it was spawned.
334 fn output_async_with_handle(&mut self, handle: &Handle) -> OutputAsync;
335}
336
337struct SpawnedChild {
338 child: imp::Child,
339 stdin: Option<imp::ChildStdin>,
340 stdout: Option<imp::ChildStdout>,
341 stderr: Option<imp::ChildStderr>,
342}
343
344impl CommandExt for Command {
345 fn spawn_async_with_handle(&mut self, handle: &Handle) -> io::Result<Child> {
346 imp::spawn_child(self, handle).map(|spawned_child| Child {
347 child: ChildDropGuard::new(spawned_child.child),
348 stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
349 stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
350 stderr: spawned_child.stderr.map(|inner| ChildStderr { inner }),
351 })
352 }
353
354 fn status_async_with_handle(&mut self, handle: &Handle) -> io::Result<StatusAsync> {
355 self.spawn_async_with_handle(handle).map(|mut child| {
356 // Ensure we close any stdio handles so we can't deadlock
357 // waiting on the child which may be waiting to read/write
358 // to a pipe we're holding.
359 child.stdin.take();
360 child.stdout.take();
361 child.stderr.take();
362
363 StatusAsync { inner: child }
364 })
365 }
366
367 fn output_async_with_handle(&mut self, handle: &Handle) -> OutputAsync {
368 self.stdout(Stdio::piped());
369 self.stderr(Stdio::piped());
370
371 let inner = self
372 .spawn_async_with_handle(handle)
373 .into_future()
374 .and_then(Child::wait_with_output);
375
376 OutputAsync {
377 inner: Box::new(inner),
378 }
379 }
380}
381
382/// A drop guard which ensures the child process is killed on drop to maintain
383/// the contract of dropping a Future leads to "cancellation".
384#[derive(Debug)]
385struct ChildDropGuard<T: Kill> {
386 inner: T,
387 kill_on_drop: bool,
388}
389
390impl<T: Kill> ChildDropGuard<T> {
391 fn new(inner: T) -> Self {
392 Self {
393 inner,
394 kill_on_drop: true,
395 }
396 }
397
398 fn forget(&mut self) {
399 self.kill_on_drop = false;
400 }
401}
402
403impl<T: Kill> Kill for ChildDropGuard<T> {
404 fn kill(&mut self) -> io::Result<()> {
405 let ret = self.inner.kill();
406
407 if ret.is_ok() {
408 self.kill_on_drop = false;
409 }
410
411 ret
412 }
413}
414
415impl<T: Kill> Drop for ChildDropGuard<T> {
416 fn drop(&mut self) {
417 if self.kill_on_drop {
418 drop(self.kill());
419 }
420 }
421}
422
423impl<T: Future + Kill> Future for ChildDropGuard<T> {
424 type Item = T::Item;
425 type Error = T::Error;
426
427 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
428 let ret = self.inner.poll();
429
430 if let Ok(Async::Ready(_)) = ret {
431 // Avoid the overhead of trying to kill a reaped process
432 self.kill_on_drop = false;
433 }
434
435 ret
436 }
437}
438
439/// Representation of a child process spawned onto an event loop.
440///
441/// This type is also a future which will yield the `ExitStatus` of the
442/// underlying child process. A `Child` here also provides access to information
443/// like the OS-assigned identifier and the stdio streams.
444///
445/// > **Note**: The behavior of `drop` on a child in this crate is *different
446/// > than the behavior of the standard library*. If a `tokio_process::Child` is
447/// > dropped before the process finishes then the process will be terminated.
448/// > In the standard library, however, the process continues executing. This is
449/// > done because futures in general take `drop` as a sign of cancellation, and
450/// > this `Child` is itself a future. If you'd like to run a process in the
451/// > background, though, you may use the `forget` method.
452#[must_use = "futures do nothing unless polled"]
453#[derive(Debug)]
454pub struct Child {
455 child: ChildDropGuard<imp::Child>,
456 stdin: Option<ChildStdin>,
457 stdout: Option<ChildStdout>,
458 stderr: Option<ChildStderr>,
459}
460
461impl Child {
462 /// Returns the OS-assigned process identifier associated with this child.
463 pub fn id(&self) -> u32 {
464 self.child.inner.id()
465 }
466
467 /// Forces the child to exit.
468 ///
469 /// This is equivalent to sending a SIGKILL on unix platforms.
470 pub fn kill(&mut self) -> io::Result<()> {
471 self.child.kill()
472 }
473
474 /// Returns a handle for writing to the child's stdin, if it has been
475 /// captured
476 pub fn stdin(&mut self) -> &mut Option<ChildStdin> {
477 &mut self.stdin
478 }
479
480 /// Returns a handle for writing to the child's stdout, if it has been
481 /// captured
482 pub fn stdout(&mut self) -> &mut Option<ChildStdout> {
483 &mut self.stdout
484 }
485
486 /// Returns a handle for writing to the child's stderr, if it has been
487 /// captured
488 pub fn stderr(&mut self) -> &mut Option<ChildStderr> {
489 &mut self.stderr
490 }
491
492 /// Returns a future that will resolve to an `Output`, containing the exit
493 /// status, stdout, and stderr of the child process.
494 ///
495 /// The returned future will simultaneously waits for the child to exit and
496 /// collect all remaining output on the stdout/stderr handles, returning an
497 /// `Output` instance.
498 ///
499 /// The stdin handle to the child process, if any, will be closed before
500 /// waiting. This helps avoid deadlock: it ensures that the child does not
501 /// block waiting for input from the parent, while the parent waits for the
502 /// child to exit.
503 ///
504 /// By default, stdin, stdout and stderr are inherited from the parent. In
505 /// order to capture the output into this `Output` it is necessary to create
506 /// new pipes between parent and child. Use `stdout(Stdio::piped())` or
507 /// `stderr(Stdio::piped())`, respectively, when creating a `Command`.
508 pub fn wait_with_output(mut self) -> WaitWithOutput {
509 drop(self.stdin().take());
510 let stdout = match self.stdout().take() {
511 Some(io) => Either::A(read_to_end(io, Vec::new()).map(|p| p.1)),
512 None => Either::B(ok(Vec::new())),
513 };
514 let stderr = match self.stderr().take() {
515 Some(io) => Either::A(read_to_end(io, Vec::new()).map(|p| p.1)),
516 None => Either::B(ok(Vec::new())),
517 };
518
519 WaitWithOutput {
520 inner: Box::new(
521 self.join3(stdout, stderr)
522 .map(|(status, stdout, stderr)| Output {
523 status,
524 stdout,
525 stderr,
526 }),
527 ),
528 }
529 }
530
531 /// Drop this `Child` without killing the underlying process.
532 ///
533 /// Normally a `Child` is killed if it's still alive when dropped, but this
534 /// method will ensure that the child may continue running once the `Child`
535 /// instance is dropped.
536 ///
537 /// > **Note**: this method may leak OS resources depending on your platform.
538 /// > To ensure resources are eventually cleaned up, consider sending the
539 /// > `Child` instance into an event loop as an alternative to this method.
540 ///
541 /// ```no_run
542 /// # extern crate futures;
543 /// # extern crate tokio;
544 /// # extern crate tokio_process;
545 /// #
546 /// # use std::process::Command;
547 /// #
548 /// # use futures::Future;
549 /// # use tokio_process::CommandExt;
550 /// #
551 /// # fn main() {
552 /// let child = Command::new("echo").arg("hello").arg("world")
553 /// .spawn_async()
554 /// .expect("failed to spawn");
555 ///
556 /// let do_cleanup = child.map(|_| ()) // Ignore result
557 /// .map_err(|_| ()); // Ignore errors
558 ///
559 /// tokio::spawn(do_cleanup);
560 /// # }
561 /// ```
562 pub fn forget(mut self) {
563 self.child.forget();
564 }
565}
566
567impl Future for Child {
568 type Item = ExitStatus;
569 type Error = io::Error;
570
571 fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
572 self.child.poll()
573 }
574}
575
576/// Future returned from the `Child::wait_with_output` method.
577///
578/// This future will resolve to the standard library's `Output` type which
579/// contains the exit status, stdout, and stderr of a child process.
580#[must_use = "futures do nothing unless polled"]
581pub struct WaitWithOutput {
582 inner: IoFuture<Output>,
583}
584
585impl fmt::Debug for WaitWithOutput {
586 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
587 fmt.debug_struct("WaitWithOutput")
588 .field("inner", &"..")
589 .finish()
590 }
591}
592
593impl Future for WaitWithOutput {
594 type Item = Output;
595 type Error = io::Error;
596
597 fn poll(&mut self) -> Poll<Output, io::Error> {
598 self.inner.poll()
599 }
600}
601
602#[doc(hidden)]
603#[deprecated(note = "renamed to `StatusAsync`", since = "0.2.1")]
604pub type StatusAsync2 = StatusAsync;
605
606/// Future returned by the `CommandExt::status_async` method.
607///
608/// This future is used to conveniently spawn a child and simply wait for its
609/// exit status. This future will resolves to the `ExitStatus` type in the
610/// standard library.
611#[must_use = "futures do nothing unless polled"]
612#[derive(Debug)]
613pub struct StatusAsync {
614 inner: Child,
615}
616
617impl Future for StatusAsync {
618 type Item = ExitStatus;
619 type Error = io::Error;
620
621 fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
622 self.inner.poll()
623 }
624}
625
626/// Future returned by the `CommandExt::output_async` method.
627///
628/// This future is mostly equivalent to spawning a process and then calling
629/// `wait_with_output` on it internally. This can be useful to simply spawn a
630/// process, collecting all of its output and its exit status.
631#[must_use = "futures do nothing unless polled"]
632pub struct OutputAsync {
633 inner: IoFuture<Output>,
634}
635
636impl fmt::Debug for OutputAsync {
637 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
638 fmt.debug_struct("OutputAsync")
639 .field("inner", &"..")
640 .finish()
641 }
642}
643
644impl Future for OutputAsync {
645 type Item = Output;
646 type Error = io::Error;
647
648 fn poll(&mut self) -> Poll<Output, io::Error> {
649 self.inner.poll()
650 }
651}
652
653/// The standard input stream for spawned children.
654///
655/// This type implements the `Write` trait to pass data to the stdin handle of
656/// a child process. Note that this type is also "futures aware" meaning that it
657/// is both (a) nonblocking and (b) will panic if used off of a future's task.
658#[derive(Debug)]
659pub struct ChildStdin {
660 inner: imp::ChildStdin,
661}
662
663/// The standard output stream for spawned children.
664///
665/// This type implements the `Read` trait to read data from the stdout handle
666/// of a child process. Note that this type is also "futures aware" meaning
667/// that it is both (a) nonblocking and (b) will panic if used off of a
668/// future's task.
669#[derive(Debug)]
670pub struct ChildStdout {
671 inner: imp::ChildStdout,
672}
673
674/// The standard error stream for spawned children.
675///
676/// This type implements the `Read` trait to read data from the stderr handle
677/// of a child process. Note that this type is also "futures aware" meaning
678/// that it is both (a) nonblocking and (b) will panic if used off of a
679/// future's task.
680#[derive(Debug)]
681pub struct ChildStderr {
682 inner: imp::ChildStderr,
683}
684
685impl Write for ChildStdin {
686 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
687 self.inner.write(bytes)
688 }
689
690 fn flush(&mut self) -> io::Result<()> {
691 self.inner.flush()
692 }
693}
694
695impl AsyncWrite for ChildStdin {
696 fn shutdown(&mut self) -> Poll<(), io::Error> {
697 self.inner.shutdown()
698 }
699}
700
701impl Read for ChildStdout {
702 fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
703 self.inner.read(bytes)
704 }
705}
706
707impl AsyncRead for ChildStdout {}
708
709impl Read for ChildStderr {
710 fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
711 self.inner.read(bytes)
712 }
713}
714
715impl AsyncRead for ChildStderr {}
716
717#[cfg(unix)]
718mod sys {
719 use super::{ChildStderr, ChildStdin, ChildStdout};
720 use std::os::unix::io::{AsRawFd, RawFd};
721
722 impl AsRawFd for ChildStdin {
723 fn as_raw_fd(&self) -> RawFd {
724 self.inner.get_ref().as_raw_fd()
725 }
726 }
727
728 impl AsRawFd for ChildStdout {
729 fn as_raw_fd(&self) -> RawFd {
730 self.inner.get_ref().as_raw_fd()
731 }
732 }
733
734 impl AsRawFd for ChildStderr {
735 fn as_raw_fd(&self) -> RawFd {
736 self.inner.get_ref().as_raw_fd()
737 }
738 }
739}
740
741#[cfg(windows)]
742mod sys {
743 use super::{ChildStderr, ChildStdin, ChildStdout};
744 use std::os::windows::io::{AsRawHandle, RawHandle};
745
746 impl AsRawHandle for ChildStdin {
747 fn as_raw_handle(&self) -> RawHandle {
748 self.inner.get_ref().as_raw_handle()
749 }
750 }
751
752 impl AsRawHandle for ChildStdout {
753 fn as_raw_handle(&self) -> RawHandle {
754 self.inner.get_ref().as_raw_handle()
755 }
756 }
757
758 impl AsRawHandle for ChildStderr {
759 fn as_raw_handle(&self) -> RawHandle {
760 self.inner.get_ref().as_raw_handle()
761 }
762 }
763}
764
765#[cfg(test)]
766mod test {
767 use super::ChildDropGuard;
768 use crate::kill::Kill;
769 use futures::{Async, Future, Poll};
770 use std::io;
771
772 struct Mock {
773 num_kills: usize,
774 num_polls: usize,
775 poll_result: Poll<(), ()>,
776 }
777
778 impl Mock {
779 fn new() -> Self {
780 Self::with_result(Ok(Async::NotReady))
781 }
782
783 fn with_result(result: Poll<(), ()>) -> Self {
784 Self {
785 num_kills: 0,
786 num_polls: 0,
787 poll_result: result,
788 }
789 }
790 }
791
792 impl Kill for Mock {
793 fn kill(&mut self) -> io::Result<()> {
794 self.num_kills += 1;
795 Ok(())
796 }
797 }
798
799 impl Future for Mock {
800 type Item = ();
801 type Error = ();
802
803 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
804 self.num_polls += 1;
805 self.poll_result
806 }
807 }
808
809 #[test]
810 fn kills_on_drop() {
811 let mut mock = Mock::new();
812
813 {
814 let guard = ChildDropGuard::new(&mut mock);
815 drop(guard);
816 }
817
818 assert_eq!(1, mock.num_kills);
819 assert_eq!(0, mock.num_polls);
820 }
821
822 #[test]
823 fn no_kill_if_already_killed() {
824 let mut mock = Mock::new();
825
826 {
827 let mut guard = ChildDropGuard::new(&mut mock);
828 let _ = guard.kill();
829 drop(guard);
830 }
831
832 assert_eq!(1, mock.num_kills);
833 assert_eq!(0, mock.num_polls);
834 }
835
836 #[test]
837 fn no_kill_if_reaped() {
838 let mut mock_pending = Mock::with_result(Ok(Async::NotReady));
839 let mut mock_reaped = Mock::with_result(Ok(Async::Ready(())));
840 let mut mock_err = Mock::with_result(Err(()));
841
842 {
843 let mut guard = ChildDropGuard::new(&mut mock_pending);
844 let _ = guard.poll();
845
846 let mut guard = ChildDropGuard::new(&mut mock_reaped);
847 let _ = guard.poll();
848
849 let mut guard = ChildDropGuard::new(&mut mock_err);
850 let _ = guard.poll();
851 }
852
853 assert_eq!(1, mock_pending.num_kills);
854 assert_eq!(1, mock_pending.num_polls);
855
856 assert_eq!(0, mock_reaped.num_kills);
857 assert_eq!(1, mock_reaped.num_polls);
858
859 assert_eq!(1, mock_err.num_kills);
860 assert_eq!(1, mock_err.num_polls);
861 }
862
863 #[test]
864 fn no_kill_on_forget() {
865 let mut mock = Mock::new();
866
867 {
868 let mut guard = ChildDropGuard::new(&mut mock);
869 guard.forget();
870 drop(guard);
871 }
872
873 assert_eq!(0, mock.num_kills);
874 assert_eq!(0, mock.num_polls);
875 }
876}