1 //! An implementation of asynchronous process management for Tokio.
2 //!
3 //! This module provides a [`Command`] struct that imitates the interface of the
4 //! [`std::process::Command`] type in the standard library, but provides asynchronous versions of
5 //! functions that create processes. These functions (`spawn`, `status`, `output` and their
6 //! variants) return "future aware" types that interoperate with Tokio. The asynchronous process
7 //! support is provided through signal handling on Unix and system APIs on Windows.
8 //!
9 //! [`std::process::Command`]: std::process::Command
10 //!
11 //! # Examples
12 //!
13 //! Here's an example program which will spawn `echo hello world` and then wait
14 //! for it complete.
15 //!
16 //! ```no_run
17 //! use tokio::process::Command;
18 //!
19 //! #[tokio::main]
20 //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
21 //!     // The usage is similar as with the standard library's `Command` type
22 //!     let mut child = Command::new("echo")
23 //!         .arg("hello")
24 //!         .arg("world")
25 //!         .spawn()
26 //!         .expect("failed to spawn");
27 //!
28 //!     // Await until the command completes
29 //!     let status = child.wait().await?;
30 //!     println!("the command exited with: {}", status);
31 //!     Ok(())
32 //! }
33 //! ```
34 //!
35 //! Next, let's take a look at an example where we not only spawn `echo hello
36 //! world` but we also capture its output.
37 //!
38 //! ```no_run
39 //! use tokio::process::Command;
40 //!
41 //! #[tokio::main]
42 //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
43 //!     // Like above, but use `output` which returns a future instead of
44 //!     // immediately returning the `Child`.
45 //!     let output = Command::new("echo").arg("hello").arg("world")
46 //!                         .output();
47 //!
48 //!     let output = output.await?;
49 //!
50 //!     assert!(output.status.success());
51 //!     assert_eq!(output.stdout, b"hello world\n");
52 //!     Ok(())
53 //! }
54 //! ```
55 //!
56 //! We can also read input line by line.
57 //!
58 //! ```no_run
59 //! use tokio::io::{BufReader, AsyncBufReadExt};
60 //! use tokio::process::Command;
61 //!
62 //! use std::process::Stdio;
63 //!
64 //! #[tokio::main]
65 //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
66 //!     let mut cmd = Command::new("cat");
67 //!
68 //!     // Specify that we want the command's standard output piped back to us.
69 //!     // By default, standard input/output/error will be inherited from the
70 //!     // current process (for example, this means that standard input will
71 //!     // come from the keyboard and standard output/error will go directly to
72 //!     // the terminal if this process is invoked from the command line).
73 //!     cmd.stdout(Stdio::piped());
74 //!
75 //!     let mut child = cmd.spawn()
76 //!         .expect("failed to spawn command");
77 //!
78 //!     let stdout = child.stdout.take()
79 //!         .expect("child did not have a handle to stdout");
80 //!
81 //!     let mut reader = BufReader::new(stdout).lines();
82 //!
83 //!     // Ensure the child process is spawned in the runtime so it can
84 //!     // make progress on its own while we await for any output.
85 //!     tokio::spawn(async move {
86 //!         let status = child.wait().await
87 //!             .expect("child process encountered an error");
88 //!
89 //!         println!("child status was: {}", status);
90 //!     });
91 //!
92 //!     while let Some(line) = reader.next_line().await? {
93 //!         println!("Line: {}", line);
94 //!     }
95 //!
96 //!     Ok(())
97 //! }
98 //! ```
99 //!
100 //! With some coordination, we can also pipe the output of one command into
101 //! another.
102 //!
103 //! ```no_run
104 //! use tokio::join;
105 //! use tokio::process::Command;
106 //! use std::convert::TryInto;
107 //! use std::process::Stdio;
108 //!
109 //! #[tokio::main]
110 //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
111 //!     let mut echo = Command::new("echo")
112 //!         .arg("hello world!")
113 //!         .stdout(Stdio::piped())
114 //!         .spawn()
115 //!         .expect("failed to spawn echo");
116 //!
117 //!     let tr_stdin: Stdio = echo
118 //!         .stdout
119 //!         .take()
120 //!         .unwrap()
121 //!         .try_into()
122 //!         .expect("failed to convert to Stdio");
123 //!
124 //!     let tr = Command::new("tr")
125 //!         .arg("a-z")
126 //!         .arg("A-Z")
127 //!         .stdin(tr_stdin)
128 //!         .stdout(Stdio::piped())
129 //!         .spawn()
130 //!         .expect("failed to spawn tr");
131 //!
132 //!     let (echo_result, tr_output) = join!(echo.wait(), tr.wait_with_output());
133 //!
134 //!     assert!(echo_result.unwrap().success());
135 //!
136 //!     let tr_output = tr_output.expect("failed to await tr");
137 //!     assert!(tr_output.status.success());
138 //!
139 //!     assert_eq!(tr_output.stdout, b"HELLO WORLD!\n");
140 //!
141 //!     Ok(())
142 //! }
143 //! ```
144 //!
145 //! # Caveats
146 //!
147 //! ## Dropping/Cancellation
148 //!
149 //! Similar to the behavior to the standard library, and unlike the futures
150 //! paradigm of dropping-implies-cancellation, a spawned process will, by
151 //! default, continue to execute even after the `Child` handle has been dropped.
152 //!
153 //! The [`Command::kill_on_drop`] method can be used to modify this behavior
154 //! and kill the child process if the `Child` wrapper is dropped before it
155 //! has exited.
156 //!
157 //! ## Unix Processes
158 //!
159 //! On Unix platforms processes must be "reaped" by their parent process after
160 //! they have exited in order to release all OS resources. A child process which
161 //! has exited, but has not yet been reaped by its parent is considered a "zombie"
162 //! process. Such processes continue to count against limits imposed by the system,
163 //! and having too many zombie processes present can prevent additional processes
164 //! from being spawned.
165 //!
166 //! The tokio runtime will, on a best-effort basis, attempt to reap and clean up
167 //! any process which it has spawned. No additional guarantees are made with regards
168 //! how quickly or how often this procedure will take place.
169 //!
170 //! It is recommended to avoid dropping a [`Child`] process handle before it has been
171 //! fully `await`ed if stricter cleanup guarantees are required.
172 //!
173 //! [`Command`]: crate::process::Command
174 //! [`Command::kill_on_drop`]: crate::process::Command::kill_on_drop
175 //! [`Child`]: crate::process::Child
176 
177 #[path = "unix/mod.rs"]
178 #[cfg(unix)]
179 mod imp;
180 
181 #[cfg(unix)]
182 pub(crate) mod unix {
183     pub(crate) use super::imp::*;
184 }
185 
186 #[path = "windows.rs"]
187 #[cfg(windows)]
188 mod imp;
189 
190 mod kill;
191 
192 use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
193 use crate::process::kill::Kill;
194 
195 use std::convert::TryInto;
196 use std::ffi::OsStr;
197 use std::future::Future;
198 use std::io;
199 #[cfg(unix)]
200 use std::os::unix::process::CommandExt;
201 #[cfg(windows)]
202 use std::os::windows::io::{AsRawHandle, RawHandle};
203 #[cfg(windows)]
204 use std::os::windows::process::CommandExt;
205 use std::path::Path;
206 use std::pin::Pin;
207 use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
208 use std::task::Context;
209 use std::task::Poll;
210 
211 /// This structure mimics the API of [`std::process::Command`] found in the standard library, but
212 /// replaces functions that create a process with an asynchronous variant. The main provided
213 /// asynchronous functions are [spawn](Command::spawn), [status](Command::status), and
214 /// [output](Command::output).
215 ///
216 /// `Command` uses asynchronous versions of some `std` types (for example [`Child`]).
217 ///
218 /// [`std::process::Command`]: std::process::Command
219 /// [`Child`]: struct@Child
220 #[derive(Debug)]
221 pub struct Command {
222     std: StdCommand,
223     kill_on_drop: bool,
224 }
225 
226 pub(crate) struct SpawnedChild {
227     child: imp::Child,
228     stdin: Option<imp::ChildStdio>,
229     stdout: Option<imp::ChildStdio>,
230     stderr: Option<imp::ChildStdio>,
231 }
232 
233 impl Command {
234     /// Constructs a new `Command` for launching the program at
235     /// path `program`, with the following default configuration:
236     ///
237     /// * No arguments to the program
238     /// * Inherit the current process's environment
239     /// * Inherit the current process's working directory
240     /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
241     ///
242     /// Builder methods are provided to change these defaults and
243     /// otherwise configure the process.
244     ///
245     /// If `program` is not an absolute path, the `PATH` will be searched in
246     /// an OS-defined way.
247     ///
248     /// The search path to be used may be controlled by setting the
249     /// `PATH` environment variable on the Command,
250     /// but this has some implementation limitations on Windows
251     /// (see issue [rust-lang/rust#37519]).
252     ///
253     /// # Examples
254     ///
255     /// Basic usage:
256     ///
257     /// ```no_run
258     /// use tokio::process::Command;
259     /// let command = Command::new("sh");
260     /// ```
261     ///
262     /// [rust-lang/rust#37519]: https://github.com/rust-lang/rust/issues/37519
263     pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
264         Self::from(StdCommand::new(program))
265     }
266 
267     /// Adds an argument to pass to the program.
268     ///
269     /// Only one argument can be passed per use. So instead of:
270     ///
271     /// ```no_run
272     /// tokio::process::Command::new("sh")
273     ///   .arg("-C /path/to/repo");
274     /// ```
275     ///
276     /// usage would be:
277     ///
278     /// ```no_run
279     /// tokio::process::Command::new("sh")
280     ///   .arg("-C")
281     ///   .arg("/path/to/repo");
282     /// ```
283     ///
284     /// To pass multiple arguments see [`args`].
285     ///
286     /// [`args`]: method@Self::args
287     ///
288     /// # Examples
289     ///
290     /// Basic usage:
291     ///
292     /// ```no_run
293     /// use tokio::process::Command;
294     ///
295     /// let command = Command::new("ls")
296     ///         .arg("-l")
297     ///         .arg("-a");
298     /// ```
299     pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
300         self.std.arg(arg);
301         self
302     }
303 
304     /// Adds multiple arguments to pass to the program.
305     ///
306     /// To pass a single argument see [`arg`].
307     ///
308     /// [`arg`]: method@Self::arg
309     ///
310     /// # Examples
311     ///
312     /// Basic usage:
313     ///
314     /// ```no_run
315     /// use tokio::process::Command;
316     ///
317     /// let command = Command::new("ls")
318     ///         .args(&["-l", "-a"]);
319     /// ```
320     pub fn args<I, S>(&mut self, args: I) -> &mut Command
321     where
322         I: IntoIterator<Item = S>,
323         S: AsRef<OsStr>,
324     {
325         self.std.args(args);
326         self
327     }
328 
329     /// Inserts or updates an environment variable mapping.
330     ///
331     /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
332     /// and case-sensitive on all other platforms.
333     ///
334     /// # Examples
335     ///
336     /// Basic usage:
337     ///
338     /// ```no_run
339     /// use tokio::process::Command;
340     ///
341     /// let command = Command::new("ls")
342     ///         .env("PATH", "/bin");
343     /// ```
344     pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
345     where
346         K: AsRef<OsStr>,
347         V: AsRef<OsStr>,
348     {
349         self.std.env(key, val);
350         self
351     }
352 
353     /// Adds or updates multiple environment variable mappings.
354     ///
355     /// # Examples
356     ///
357     /// Basic usage:
358     ///
359     /// ```no_run
360     /// use tokio::process::Command;
361     /// use std::process::{Stdio};
362     /// use std::env;
363     /// use std::collections::HashMap;
364     ///
365     /// let filtered_env : HashMap<String, String> =
366     ///     env::vars().filter(|&(ref k, _)|
367     ///         k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH"
368     ///     ).collect();
369     ///
370     /// let command = Command::new("printenv")
371     ///         .stdin(Stdio::null())
372     ///         .stdout(Stdio::inherit())
373     ///         .env_clear()
374     ///         .envs(&filtered_env);
375     /// ```
376     pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
377     where
378         I: IntoIterator<Item = (K, V)>,
379         K: AsRef<OsStr>,
380         V: AsRef<OsStr>,
381     {
382         self.std.envs(vars);
383         self
384     }
385 
386     /// Removes an environment variable mapping.
387     ///
388     /// # Examples
389     ///
390     /// Basic usage:
391     ///
392     /// ```no_run
393     /// use tokio::process::Command;
394     ///
395     /// let command = Command::new("ls")
396     ///         .env_remove("PATH");
397     /// ```
398     pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
399         self.std.env_remove(key);
400         self
401     }
402 
403     /// Clears the entire environment map for the child process.
404     ///
405     /// # Examples
406     ///
407     /// Basic usage:
408     ///
409     /// ```no_run
410     /// use tokio::process::Command;
411     ///
412     /// let command = Command::new("ls")
413     ///         .env_clear();
414     /// ```
415     pub fn env_clear(&mut self) -> &mut Command {
416         self.std.env_clear();
417         self
418     }
419 
420     /// Sets the working directory for the child process.
421     ///
422     /// # Platform-specific behavior
423     ///
424     /// If the program path is relative (e.g., `"./script.sh"`), it's ambiguous
425     /// whether it should be interpreted relative to the parent's working
426     /// directory or relative to `current_dir`. The behavior in this case is
427     /// platform specific and unstable, and it's recommended to use
428     /// [`canonicalize`] to get an absolute program path instead.
429     ///
430     /// [`canonicalize`]: crate::fs::canonicalize()
431     ///
432     /// # Examples
433     ///
434     /// Basic usage:
435     ///
436     /// ```no_run
437     /// use tokio::process::Command;
438     ///
439     /// let command = Command::new("ls")
440     ///         .current_dir("/bin");
441     /// ```
442     pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
443         self.std.current_dir(dir);
444         self
445     }
446 
447     /// Sets configuration for the child process's standard input (stdin) handle.
448     ///
449     /// Defaults to [`inherit`] when used with `spawn` or `status`, and
450     /// defaults to [`piped`] when used with `output`.
451     ///
452     /// [`inherit`]: std::process::Stdio::inherit
453     /// [`piped`]: std::process::Stdio::piped
454     ///
455     /// # Examples
456     ///
457     /// Basic usage:
458     ///
459     /// ```no_run
460     /// use std::process::{Stdio};
461     /// use tokio::process::Command;
462     ///
463     /// let command = Command::new("ls")
464     ///         .stdin(Stdio::null());
465     /// ```
466     pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
467         self.std.stdin(cfg);
468         self
469     }
470 
471     /// Sets configuration for the child process's standard output (stdout) handle.
472     ///
473     /// Defaults to [`inherit`] when used with `spawn` or `status`, and
474     /// defaults to [`piped`] when used with `output`.
475     ///
476     /// [`inherit`]: std::process::Stdio::inherit
477     /// [`piped`]: std::process::Stdio::piped
478     ///
479     /// # Examples
480     ///
481     /// Basic usage:
482     ///
483     /// ```no_run
484     /// use tokio::process::Command;
485     /// use std::process::Stdio;
486     ///
487     /// let command = Command::new("ls")
488     ///         .stdout(Stdio::null());
489     /// ```
490     pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
491         self.std.stdout(cfg);
492         self
493     }
494 
495     /// Sets configuration for the child process's standard error (stderr) handle.
496     ///
497     /// Defaults to [`inherit`] when used with `spawn` or `status`, and
498     /// defaults to [`piped`] when used with `output`.
499     ///
500     /// [`inherit`]: std::process::Stdio::inherit
501     /// [`piped`]: std::process::Stdio::piped
502     ///
503     /// # Examples
504     ///
505     /// Basic usage:
506     ///
507     /// ```no_run
508     /// use tokio::process::Command;
509     /// use std::process::{Stdio};
510     ///
511     /// let command = Command::new("ls")
512     ///         .stderr(Stdio::null());
513     /// ```
514     pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
515         self.std.stderr(cfg);
516         self
517     }
518 
519     /// Controls whether a `kill` operation should be invoked on a spawned child
520     /// process when its corresponding `Child` handle is dropped.
521     ///
522     /// By default, this value is assumed to be `false`, meaning the next spawned
523     /// process will not be killed on drop, similar to the behavior of the standard
524     /// library.
525     ///
526     /// # Caveats
527     ///
528     /// On Unix platforms processes must be "reaped" by their parent process after
529     /// they have exited in order to release all OS resources. A child process which
530     /// has exited, but has not yet been reaped by its parent is considered a "zombie"
531     /// process. Such processes continue to count against limits imposed by the system,
532     /// and having too many zombie processes present can prevent additional processes
533     /// from being spawned.
534     ///
535     /// Although issuing a `kill` signal to the child process is a synchronous
536     /// operation, the resulting zombie process cannot be `.await`ed inside of the
537     /// destructor to avoid blocking other tasks. The tokio runtime will, on a
538     /// best-effort basis, attempt to reap and clean up such processes in the
539     /// background, but makes no additional guarantees are made with regards
540     /// how quickly or how often this procedure will take place.
541     ///
542     /// If stronger guarantees are required, it is recommended to avoid dropping
543     /// a [`Child`] handle where possible, and instead utilize `child.wait().await`
544     /// or `child.kill().await` where possible.
545     pub fn kill_on_drop(&mut self, kill_on_drop: bool) -> &mut Command {
546         self.kill_on_drop = kill_on_drop;
547         self
548     }
549 
550     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
551     ///
552     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
553     ///
554     /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
555     #[cfg(windows)]
556     #[cfg_attr(docsrs, doc(cfg(windows)))]
557     pub fn creation_flags(&mut self, flags: u32) -> &mut Command {
558         self.std.creation_flags(flags);
559         self
560     }
561 
562     /// Sets the child process's user ID. This translates to a
563     /// `setuid` call in the child process. Failure in the `setuid`
564     /// call will cause the spawn to fail.
565     #[cfg(unix)]
566     #[cfg_attr(docsrs, doc(cfg(unix)))]
567     pub fn uid(&mut self, id: u32) -> &mut Command {
568         self.std.uid(id);
569         self
570     }
571 
572     /// Similar to `uid` but sets the group ID of the child process. This has
573     /// the same semantics as the `uid` field.
574     #[cfg(unix)]
575     #[cfg_attr(docsrs, doc(cfg(unix)))]
576     pub fn gid(&mut self, id: u32) -> &mut Command {
577         self.std.gid(id);
578         self
579     }
580 
581     /// Sets executable argument.
582     ///
583     /// Set the first process argument, `argv[0]`, to something other than the
584     /// default executable path.
585     #[cfg(unix)]
586     #[cfg_attr(docsrs, doc(cfg(unix)))]
587     pub fn arg0<S>(&mut self, arg: S) -> &mut Command
588     where
589         S: AsRef<OsStr>,
590     {
591         self.std.arg0(arg);
592         self
593     }
594 
595     /// Schedules a closure to be run just before the `exec` function is
596     /// invoked.
597     ///
598     /// The closure is allowed to return an I/O error whose OS error code will
599     /// be communicated back to the parent and returned as an error from when
600     /// the spawn was requested.
601     ///
602     /// Multiple closures can be registered and they will be called in order of
603     /// their registration. If a closure returns `Err` then no further closures
604     /// will be called and the spawn operation will immediately return with a
605     /// failure.
606     ///
607     /// # Safety
608     ///
609     /// This closure will be run in the context of the child process after a
610     /// `fork`. This primarily means that any modifications made to memory on
611     /// behalf of this closure will **not** be visible to the parent process.
612     /// This is often a very constrained environment where normal operations
613     /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
614     /// other threads perhaps still running when the `fork` was run).
615     ///
616     /// This also means that all resources such as file descriptors and
617     /// memory-mapped regions got duplicated. It is your responsibility to make
618     /// sure that the closure does not violate library invariants by making
619     /// invalid use of these duplicates.
620     ///
621     /// When this closure is run, aspects such as the stdio file descriptors and
622     /// working directory have successfully been changed, so output to these
623     /// locations may not appear where intended.
624     #[cfg(unix)]
625     #[cfg_attr(docsrs, doc(cfg(unix)))]
626     pub unsafe fn pre_exec<F>(&mut self, f: F) -> &mut Command
627     where
628         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
629     {
630         self.std.pre_exec(f);
631         self
632     }
633 
634     /// Executes the command as a child process, returning a handle to it.
635     ///
636     /// By default, stdin, stdout and stderr are inherited from the parent.
637     ///
638     /// This method will spawn the child process synchronously and return a
639     /// handle to a future-aware child process. The `Child` returned implements
640     /// `Future` itself to acquire the `ExitStatus` of the child, and otherwise
641     /// the `Child` has methods to acquire handles to the stdin, stdout, and
642     /// stderr streams.
643     ///
644     /// All I/O this child does will be associated with the current default
645     /// event loop.
646     ///
647     /// # Examples
648     ///
649     /// Basic usage:
650     ///
651     /// ```no_run
652     /// use tokio::process::Command;
653     ///
654     /// async fn run_ls() -> std::process::ExitStatus {
655     ///     Command::new("ls")
656     ///         .spawn()
657     ///         .expect("ls command failed to start")
658     ///         .wait()
659     ///         .await
660     ///         .expect("ls command failed to run")
661     /// }
662     /// ```
663     ///
664     /// # Caveats
665     ///
666     /// ## Dropping/Cancellation
667     ///
668     /// Similar to the behavior to the standard library, and unlike the futures
669     /// paradigm of dropping-implies-cancellation, a spawned process will, by
670     /// default, continue to execute even after the `Child` handle has been dropped.
671     ///
672     /// The [`Command::kill_on_drop`] method can be used to modify this behavior
673     /// and kill the child process if the `Child` wrapper is dropped before it
674     /// has exited.
675     ///
676     /// ## Unix Processes
677     ///
678     /// On Unix platforms processes must be "reaped" by their parent process after
679     /// they have exited in order to release all OS resources. A child process which
680     /// has exited, but has not yet been reaped by its parent is considered a "zombie"
681     /// process. Such processes continue to count against limits imposed by the system,
682     /// and having too many zombie processes present can prevent additional processes
683     /// from being spawned.
684     ///
685     /// The tokio runtime will, on a best-effort basis, attempt to reap and clean up
686     /// any process which it has spawned. No additional guarantees are made with regards
687     /// how quickly or how often this procedure will take place.
688     ///
689     /// It is recommended to avoid dropping a [`Child`] process handle before it has been
690     /// fully `await`ed if stricter cleanup guarantees are required.
691     ///
692     /// [`Command`]: crate::process::Command
693     /// [`Command::kill_on_drop`]: crate::process::Command::kill_on_drop
694     /// [`Child`]: crate::process::Child
695     ///
696     /// # Errors
697     ///
698     /// On Unix platforms this method will fail with `std::io::ErrorKind::WouldBlock`
699     /// if the system process limit is reached (which includes other applications
700     /// running on the system).
701     pub fn spawn(&mut self) -> io::Result<Child> {
702         imp::spawn_child(&mut self.std).map(|spawned_child| Child {
703             child: FusedChild::Child(ChildDropGuard {
704                 inner: spawned_child.child,
705                 kill_on_drop: self.kill_on_drop,
706             }),
707             stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
708             stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
709             stderr: spawned_child.stderr.map(|inner| ChildStderr { inner }),
710         })
711     }
712 
713     /// Executes the command as a child process, waiting for it to finish and
714     /// collecting its exit status.
715     ///
716     /// By default, stdin, stdout and stderr are inherited from the parent.
717     /// If any input/output handles are set to a pipe then they will be immediately
718     /// closed after the child is spawned.
719     ///
720     /// All I/O this child does will be associated with the current default
721     /// event loop.
722     ///
723     /// The destructor of the future returned by this function will kill
724     /// the child if [`kill_on_drop`] is set to true.
725     ///
726     /// [`kill_on_drop`]: fn@Self::kill_on_drop
727     ///
728     /// # Errors
729     ///
730     /// This future will return an error if the child process cannot be spawned
731     /// or if there is an error while awaiting its status.
732     ///
733     /// On Unix platforms this method will fail with `std::io::ErrorKind::WouldBlock`
734     /// if the system process limit is reached (which includes other applications
735     /// running on the system).
736     ///
737     /// # Examples
738     ///
739     /// Basic usage:
740     ///
741     /// ```no_run
742     /// use tokio::process::Command;
743     ///
744     /// async fn run_ls() -> std::process::ExitStatus {
745     ///     Command::new("ls")
746     ///         .status()
747     ///         .await
748     ///         .expect("ls command failed to run")
749     /// }
750     /// ```
751     pub fn status(&mut self) -> impl Future<Output = io::Result<ExitStatus>> {
752         let child = self.spawn();
753 
754         async {
755             let mut child = child?;
756 
757             // Ensure we close any stdio handles so we can't deadlock
758             // waiting on the child which may be waiting to read/write
759             // to a pipe we're holding.
760             child.stdin.take();
761             child.stdout.take();
762             child.stderr.take();
763 
764             child.wait().await
765         }
766     }
767 
768     /// Executes the command as a child process, waiting for it to finish and
769     /// collecting all of its output.
770     ///
771     /// > **Note**: this method, unlike the standard library, will
772     /// > unconditionally configure the stdout/stderr handles to be pipes, even
773     /// > if they have been previously configured. If this is not desired then
774     /// > the `spawn` method should be used in combination with the
775     /// > `wait_with_output` method on child.
776     ///
777     /// This method will return a future representing the collection of the
778     /// child process's stdout/stderr. It will resolve to
779     /// the `Output` type in the standard library, containing `stdout` and
780     /// `stderr` as `Vec<u8>` along with an `ExitStatus` representing how the
781     /// process exited.
782     ///
783     /// All I/O this child does will be associated with the current default
784     /// event loop.
785     ///
786     /// The destructor of the future returned by this function will kill
787     /// the child if [`kill_on_drop`] is set to true.
788     ///
789     /// [`kill_on_drop`]: fn@Self::kill_on_drop
790     ///
791     /// # Errors
792     ///
793     /// This future will return an error if the child process cannot be spawned
794     /// or if there is an error while awaiting its status.
795     ///
796     /// On Unix platforms this method will fail with `std::io::ErrorKind::WouldBlock`
797     /// if the system process limit is reached (which includes other applications
798     /// running on the system).
799     /// # Examples
800     ///
801     /// Basic usage:
802     ///
803     /// ```no_run
804     /// use tokio::process::Command;
805     ///
806     /// async fn run_ls() {
807     ///     let output: std::process::Output = Command::new("ls")
808     ///         .output()
809     ///         .await
810     ///         .expect("ls command failed to run");
811     ///     println!("stderr of ls: {:?}", output.stderr);
812     /// }
813     /// ```
814     pub fn output(&mut self) -> impl Future<Output = io::Result<Output>> {
815         self.std.stdout(Stdio::piped());
816         self.std.stderr(Stdio::piped());
817 
818         let child = self.spawn();
819 
820         async { child?.wait_with_output().await }
821     }
822 }
823 
824 impl From<StdCommand> for Command {
825     fn from(std: StdCommand) -> Command {
826         Command {
827             std,
828             kill_on_drop: false,
829         }
830     }
831 }
832 
833 /// A drop guard which can ensure the child process is killed on drop if specified.
834 #[derive(Debug)]
835 struct ChildDropGuard<T: Kill> {
836     inner: T,
837     kill_on_drop: bool,
838 }
839 
840 impl<T: Kill> Kill for ChildDropGuard<T> {
841     fn kill(&mut self) -> io::Result<()> {
842         let ret = self.inner.kill();
843 
844         if ret.is_ok() {
845             self.kill_on_drop = false;
846         }
847 
848         ret
849     }
850 }
851 
852 impl<T: Kill> Drop for ChildDropGuard<T> {
853     fn drop(&mut self) {
854         if self.kill_on_drop {
855             drop(self.kill());
856         }
857     }
858 }
859 
860 impl<T, E, F> Future for ChildDropGuard<F>
861 where
862     F: Future<Output = Result<T, E>> + Kill + Unpin,
863 {
864     type Output = Result<T, E>;
865 
866     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
867         // Keep track of task budget
868         let coop = ready!(crate::coop::poll_proceed(cx));
869 
870         let ret = Pin::new(&mut self.inner).poll(cx);
871 
872         if let Poll::Ready(Ok(_)) = ret {
873             // Avoid the overhead of trying to kill a reaped process
874             self.kill_on_drop = false;
875         }
876 
877         if ret.is_ready() {
878             coop.made_progress();
879         }
880 
881         ret
882     }
883 }
884 
885 /// Keeps track of the exit status of a child process without worrying about
886 /// polling the underlying futures even after they have completed.
887 #[derive(Debug)]
888 enum FusedChild {
889     Child(ChildDropGuard<imp::Child>),
890     Done(ExitStatus),
891 }
892 
893 /// Representation of a child process spawned onto an event loop.
894 ///
895 /// # Caveats
896 /// Similar to the behavior to the standard library, and unlike the futures
897 /// paradigm of dropping-implies-cancellation, a spawned process will, by
898 /// default, continue to execute even after the `Child` handle has been dropped.
899 ///
900 /// The `Command::kill_on_drop` method can be used to modify this behavior
901 /// and kill the child process if the `Child` wrapper is dropped before it
902 /// has exited.
903 #[derive(Debug)]
904 pub struct Child {
905     child: FusedChild,
906 
907     /// The handle for writing to the child's standard input (stdin), if it has
908     /// been captured. To avoid partially moving the `child` and thus blocking
909     /// yourself from calling functions on `child` while using `stdin`, you might
910     /// find it helpful to do:
911     ///
912     /// ```no_run
913     /// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
914     /// let stdin = child.stdin.take().unwrap();
915     /// ```
916     pub stdin: Option<ChildStdin>,
917 
918     /// The handle for reading from the child's standard output (stdout), if it
919     /// has been captured. You might find it helpful to do
920     ///
921     /// ```no_run
922     /// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
923     /// let stdout = child.stdout.take().unwrap();
924     /// ```
925     ///
926     /// to avoid partially moving the `child` and thus blocking yourself from calling
927     /// functions on `child` while using `stdout`.
928     pub stdout: Option<ChildStdout>,
929 
930     /// The handle for reading from the child's standard error (stderr), if it
931     /// has been captured. You might find it helpful to do
932     ///
933     /// ```no_run
934     /// # let mut child = tokio::process::Command::new("echo").spawn().unwrap();
935     /// let stderr = child.stderr.take().unwrap();
936     /// ```
937     ///
938     /// to avoid partially moving the `child` and thus blocking yourself from calling
939     /// functions on `child` while using `stderr`.
940     pub stderr: Option<ChildStderr>,
941 }
942 
943 impl Child {
944     /// Returns the OS-assigned process identifier associated with this child
945     /// while it is still running.
946     ///
947     /// Once the child has been polled to completion this will return `None`.
948     /// This is done to avoid confusion on platforms like Unix where the OS
949     /// identifier could be reused once the process has completed.
950     pub fn id(&self) -> Option<u32> {
951         match &self.child {
952             FusedChild::Child(child) => Some(child.inner.id()),
953             FusedChild::Done(_) => None,
954         }
955     }
956 
957     /// Extracts the raw handle of the process associated with this child while
958     /// it is still running. Returns `None` if the child has exited.
959     #[cfg(windows)]
960     pub fn raw_handle(&self) -> Option<RawHandle> {
961         match &self.child {
962             FusedChild::Child(c) => Some(c.inner.as_raw_handle()),
963             FusedChild::Done(_) => None,
964         }
965     }
966 
967     /// Attempts to force the child to exit, but does not wait for the request
968     /// to take effect.
969     ///
970     /// On Unix platforms, this is the equivalent to sending a SIGKILL. Note
971     /// that on Unix platforms it is possible for a zombie process to remain
972     /// after a kill is sent; to avoid this, the caller should ensure that either
973     /// `child.wait().await` or `child.try_wait()` is invoked successfully.
974     pub fn start_kill(&mut self) -> io::Result<()> {
975         match &mut self.child {
976             FusedChild::Child(child) => child.kill(),
977             FusedChild::Done(_) => Err(io::Error::new(
978                 io::ErrorKind::InvalidInput,
979                 "invalid argument: can't kill an exited process",
980             )),
981         }
982     }
983 
984     /// Forces the child to exit.
985     ///
986     /// This is equivalent to sending a SIGKILL on unix platforms.
987     ///
988     /// If the child has to be killed remotely, it is possible to do it using
989     /// a combination of the select! macro and a oneshot channel. In the following
990     /// example, the child will run until completion unless a message is sent on
991     /// the oneshot channel. If that happens, the child is killed immediately
992     /// using the `.kill()` method.
993     ///
994     /// ```no_run
995     /// use tokio::process::Command;
996     /// use tokio::sync::oneshot::channel;
997     ///
998     /// #[tokio::main]
999     /// async fn main() {
1000     ///     let (send, recv) = channel::<()>();
1001     ///     let mut child = Command::new("sleep").arg("1").spawn().unwrap();
1002     ///     tokio::spawn(async move { send.send(()) });
1003     ///     tokio::select! {
1004     ///         _ = child.wait() => {}
1005     ///         _ = recv => child.kill().await.expect("kill failed"),
1006     ///     }
1007     /// }
1008     /// ```
1009     pub async fn kill(&mut self) -> io::Result<()> {
1010         self.start_kill()?;
1011         self.wait().await?;
1012         Ok(())
1013     }
1014 
1015     /// Waits for the child to exit completely, returning the status that it
1016     /// exited with. This function will continue to have the same return value
1017     /// after it has been called at least once.
1018     ///
1019     /// The stdin handle to the child process, if any, will be closed
1020     /// before waiting. This helps avoid deadlock: it ensures that the
1021     /// child does not block waiting for input from the parent, while
1022     /// the parent waits for the child to exit.
1023     ///
1024     /// If the caller wishes to explicitly control when the child's stdin
1025     /// handle is closed, they may `.take()` it before calling `.wait()`:
1026     ///
1027     /// ```
1028     /// # #[cfg(not(unix))]fn main(){}
1029     /// # #[cfg(unix)]
1030     /// use tokio::io::AsyncWriteExt;
1031     /// # #[cfg(unix)]
1032     /// use tokio::process::Command;
1033     /// # #[cfg(unix)]
1034     /// use std::process::Stdio;
1035     ///
1036     /// # #[cfg(unix)]
1037     /// #[tokio::main]
1038     /// async fn main() {
1039     ///     let mut child = Command::new("cat")
1040     ///         .stdin(Stdio::piped())
1041     ///         .spawn()
1042     ///         .unwrap();
1043     ///
1044     ///     let mut stdin = child.stdin.take().unwrap();
1045     ///     tokio::spawn(async move {
1046     ///         // do something with stdin here...
1047     ///         stdin.write_all(b"hello world\n").await.unwrap();
1048     ///
1049     ///         // then drop when finished
1050     ///         drop(stdin);
1051     ///     });
1052     ///
1053     ///     // wait for the process to complete
1054     ///     let _ = child.wait().await;
1055     /// }
1056     /// ```
1057     pub async fn wait(&mut self) -> io::Result<ExitStatus> {
1058         // Ensure stdin is closed so the child isn't stuck waiting on
1059         // input while the parent is waiting for it to exit.
1060         drop(self.stdin.take());
1061 
1062         match &mut self.child {
1063             FusedChild::Done(exit) => Ok(*exit),
1064             FusedChild::Child(child) => {
1065                 let ret = child.await;
1066 
1067                 if let Ok(exit) = ret {
1068                     self.child = FusedChild::Done(exit);
1069                 }
1070 
1071                 ret
1072             }
1073         }
1074     }
1075 
1076     /// Attempts to collect the exit status of the child if it has already
1077     /// exited.
1078     ///
1079     /// This function will not block the calling thread and will only
1080     /// check to see if the child process has exited or not. If the child has
1081     /// exited then on Unix the process ID is reaped. This function is
1082     /// guaranteed to repeatedly return a successful exit status so long as the
1083     /// child has already exited.
1084     ///
1085     /// If the child has exited, then `Ok(Some(status))` is returned. If the
1086     /// exit status is not available at this time then `Ok(None)` is returned.
1087     /// If an error occurs, then that error is returned.
1088     ///
1089     /// Note that unlike `wait`, this function will not attempt to drop stdin,
1090     /// nor will it wake the current task if the child exits.
1091     pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
1092         match &mut self.child {
1093             FusedChild::Done(exit) => Ok(Some(*exit)),
1094             FusedChild::Child(guard) => {
1095                 let ret = guard.inner.try_wait();
1096 
1097                 if let Ok(Some(exit)) = ret {
1098                     // Avoid the overhead of trying to kill a reaped process
1099                     guard.kill_on_drop = false;
1100                     self.child = FusedChild::Done(exit);
1101                 }
1102 
1103                 ret
1104             }
1105         }
1106     }
1107 
1108     /// Returns a future that will resolve to an `Output`, containing the exit
1109     /// status, stdout, and stderr of the child process.
1110     ///
1111     /// The returned future will simultaneously waits for the child to exit and
1112     /// collect all remaining output on the stdout/stderr handles, returning an
1113     /// `Output` instance.
1114     ///
1115     /// The stdin handle to the child process, if any, will be closed before
1116     /// waiting. This helps avoid deadlock: it ensures that the child does not
1117     /// block waiting for input from the parent, while the parent waits for the
1118     /// child to exit.
1119     ///
1120     /// By default, stdin, stdout and stderr are inherited from the parent. In
1121     /// order to capture the output into this `Output` it is necessary to create
1122     /// new pipes between parent and child. Use `stdout(Stdio::piped())` or
1123     /// `stderr(Stdio::piped())`, respectively, when creating a `Command`.
1124     pub async fn wait_with_output(mut self) -> io::Result<Output> {
1125         use crate::future::try_join3;
1126 
1127         async fn read_to_end<A: AsyncRead + Unpin>(io: Option<A>) -> io::Result<Vec<u8>> {
1128             let mut vec = Vec::new();
1129             if let Some(mut io) = io {
1130                 crate::io::util::read_to_end(&mut io, &mut vec).await?;
1131             }
1132             Ok(vec)
1133         }
1134 
1135         let stdout_fut = read_to_end(self.stdout.take());
1136         let stderr_fut = read_to_end(self.stderr.take());
1137 
1138         let (status, stdout, stderr) = try_join3(self.wait(), stdout_fut, stderr_fut).await?;
1139 
1140         Ok(Output {
1141             status,
1142             stdout,
1143             stderr,
1144         })
1145     }
1146 }
1147 
1148 /// The standard input stream for spawned children.
1149 ///
1150 /// This type implements the `AsyncWrite` trait to pass data to the stdin handle of
1151 /// handle of a child process asynchronously.
1152 #[derive(Debug)]
1153 pub struct ChildStdin {
1154     inner: imp::ChildStdio,
1155 }
1156 
1157 /// The standard output stream for spawned children.
1158 ///
1159 /// This type implements the `AsyncRead` trait to read data from the stdout
1160 /// handle of a child process asynchronously.
1161 #[derive(Debug)]
1162 pub struct ChildStdout {
1163     inner: imp::ChildStdio,
1164 }
1165 
1166 /// The standard error stream for spawned children.
1167 ///
1168 /// This type implements the `AsyncRead` trait to read data from the stderr
1169 /// handle of a child process asynchronously.
1170 #[derive(Debug)]
1171 pub struct ChildStderr {
1172     inner: imp::ChildStdio,
1173 }
1174 
1175 impl ChildStdin {
1176     /// Creates an asynchronous `ChildStdin` from a synchronous one.
1177     ///
1178     /// # Errors
1179     ///
1180     /// This method may fail if an error is encountered when setting the pipe to
1181     /// non-blocking mode, or when registering the pipe with the runtime's IO
1182     /// driver.
1183     pub fn from_std(inner: std::process::ChildStdin) -> io::Result<Self> {
1184         Ok(Self {
1185             inner: imp::stdio(inner)?,
1186         })
1187     }
1188 }
1189 
1190 impl ChildStdout {
1191     /// Creates an asynchronous `ChildStderr` from a synchronous one.
1192     ///
1193     /// # Errors
1194     ///
1195     /// This method may fail if an error is encountered when setting the pipe to
1196     /// non-blocking mode, or when registering the pipe with the runtime's IO
1197     /// driver.
1198     pub fn from_std(inner: std::process::ChildStdout) -> io::Result<Self> {
1199         Ok(Self {
1200             inner: imp::stdio(inner)?,
1201         })
1202     }
1203 }
1204 
1205 impl ChildStderr {
1206     /// Creates an asynchronous `ChildStderr` from a synchronous one.
1207     ///
1208     /// # Errors
1209     ///
1210     /// This method may fail if an error is encountered when setting the pipe to
1211     /// non-blocking mode, or when registering the pipe with the runtime's IO
1212     /// driver.
1213     pub fn from_std(inner: std::process::ChildStderr) -> io::Result<Self> {
1214         Ok(Self {
1215             inner: imp::stdio(inner)?,
1216         })
1217     }
1218 }
1219 
1220 impl AsyncWrite for ChildStdin {
1221     fn poll_write(
1222         self: Pin<&mut Self>,
1223         cx: &mut Context<'_>,
1224         buf: &[u8],
1225     ) -> Poll<io::Result<usize>> {
1226         self.inner.poll_write(cx, buf)
1227     }
1228 
1229     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1230         Poll::Ready(Ok(()))
1231     }
1232 
1233     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1234         Poll::Ready(Ok(()))
1235     }
1236 }
1237 
1238 impl AsyncRead for ChildStdout {
1239     fn poll_read(
1240         self: Pin<&mut Self>,
1241         cx: &mut Context<'_>,
1242         buf: &mut ReadBuf<'_>,
1243     ) -> Poll<io::Result<()>> {
1244         // Safety: pipes support reading into uninitialized memory
1245         unsafe { self.inner.poll_read(cx, buf) }
1246     }
1247 }
1248 
1249 impl AsyncRead for ChildStderr {
1250     fn poll_read(
1251         self: Pin<&mut Self>,
1252         cx: &mut Context<'_>,
1253         buf: &mut ReadBuf<'_>,
1254     ) -> Poll<io::Result<()>> {
1255         // Safety: pipes support reading into uninitialized memory
1256         unsafe { self.inner.poll_read(cx, buf) }
1257     }
1258 }
1259 
1260 impl TryInto<Stdio> for ChildStdin {
1261     type Error = io::Error;
1262 
1263     fn try_into(self) -> Result<Stdio, Self::Error> {
1264         imp::convert_to_stdio(self.inner)
1265     }
1266 }
1267 
1268 impl TryInto<Stdio> for ChildStdout {
1269     type Error = io::Error;
1270 
1271     fn try_into(self) -> Result<Stdio, Self::Error> {
1272         imp::convert_to_stdio(self.inner)
1273     }
1274 }
1275 
1276 impl TryInto<Stdio> for ChildStderr {
1277     type Error = io::Error;
1278 
1279     fn try_into(self) -> Result<Stdio, Self::Error> {
1280         imp::convert_to_stdio(self.inner)
1281     }
1282 }
1283 
1284 #[cfg(unix)]
1285 mod sys {
1286     use std::os::unix::io::{AsRawFd, RawFd};
1287 
1288     use super::{ChildStderr, ChildStdin, ChildStdout};
1289 
1290     impl AsRawFd for ChildStdin {
1291         fn as_raw_fd(&self) -> RawFd {
1292             self.inner.as_raw_fd()
1293         }
1294     }
1295 
1296     impl AsRawFd for ChildStdout {
1297         fn as_raw_fd(&self) -> RawFd {
1298             self.inner.as_raw_fd()
1299         }
1300     }
1301 
1302     impl AsRawFd for ChildStderr {
1303         fn as_raw_fd(&self) -> RawFd {
1304             self.inner.as_raw_fd()
1305         }
1306     }
1307 }
1308 
1309 #[cfg(windows)]
1310 mod sys {
1311     use std::os::windows::io::{AsRawHandle, RawHandle};
1312 
1313     use super::{ChildStderr, ChildStdin, ChildStdout};
1314 
1315     impl AsRawHandle for ChildStdin {
1316         fn as_raw_handle(&self) -> RawHandle {
1317             self.inner.as_raw_handle()
1318         }
1319     }
1320 
1321     impl AsRawHandle for ChildStdout {
1322         fn as_raw_handle(&self) -> RawHandle {
1323             self.inner.as_raw_handle()
1324         }
1325     }
1326 
1327     impl AsRawHandle for ChildStderr {
1328         fn as_raw_handle(&self) -> RawHandle {
1329             self.inner.as_raw_handle()
1330         }
1331     }
1332 }
1333 
1334 #[cfg(all(test, not(loom)))]
1335 mod test {
1336     use super::kill::Kill;
1337     use super::ChildDropGuard;
1338 
1339     use futures::future::FutureExt;
1340     use std::future::Future;
1341     use std::io;
1342     use std::pin::Pin;
1343     use std::task::{Context, Poll};
1344 
1345     struct Mock {
1346         num_kills: usize,
1347         num_polls: usize,
1348         poll_result: Poll<Result<(), ()>>,
1349     }
1350 
1351     impl Mock {
1352         fn new() -> Self {
1353             Self::with_result(Poll::Pending)
1354         }
1355 
1356         fn with_result(result: Poll<Result<(), ()>>) -> Self {
1357             Self {
1358                 num_kills: 0,
1359                 num_polls: 0,
1360                 poll_result: result,
1361             }
1362         }
1363     }
1364 
1365     impl Kill for Mock {
1366         fn kill(&mut self) -> io::Result<()> {
1367             self.num_kills += 1;
1368             Ok(())
1369         }
1370     }
1371 
1372     impl Future for Mock {
1373         type Output = Result<(), ()>;
1374 
1375         fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
1376             let inner = Pin::get_mut(self);
1377             inner.num_polls += 1;
1378             inner.poll_result
1379         }
1380     }
1381 
1382     #[test]
1383     fn kills_on_drop_if_specified() {
1384         let mut mock = Mock::new();
1385 
1386         {
1387             let guard = ChildDropGuard {
1388                 inner: &mut mock,
1389                 kill_on_drop: true,
1390             };
1391             drop(guard);
1392         }
1393 
1394         assert_eq!(1, mock.num_kills);
1395         assert_eq!(0, mock.num_polls);
1396     }
1397 
1398     #[test]
1399     fn no_kill_on_drop_by_default() {
1400         let mut mock = Mock::new();
1401 
1402         {
1403             let guard = ChildDropGuard {
1404                 inner: &mut mock,
1405                 kill_on_drop: false,
1406             };
1407             drop(guard);
1408         }
1409 
1410         assert_eq!(0, mock.num_kills);
1411         assert_eq!(0, mock.num_polls);
1412     }
1413 
1414     #[test]
1415     fn no_kill_if_already_killed() {
1416         let mut mock = Mock::new();
1417 
1418         {
1419             let mut guard = ChildDropGuard {
1420                 inner: &mut mock,
1421                 kill_on_drop: true,
1422             };
1423             let _ = guard.kill();
1424             drop(guard);
1425         }
1426 
1427         assert_eq!(1, mock.num_kills);
1428         assert_eq!(0, mock.num_polls);
1429     }
1430 
1431     #[test]
1432     fn no_kill_if_reaped() {
1433         let mut mock_pending = Mock::with_result(Poll::Pending);
1434         let mut mock_reaped = Mock::with_result(Poll::Ready(Ok(())));
1435         let mut mock_err = Mock::with_result(Poll::Ready(Err(())));
1436 
1437         let waker = futures::task::noop_waker();
1438         let mut context = Context::from_waker(&waker);
1439         {
1440             let mut guard = ChildDropGuard {
1441                 inner: &mut mock_pending,
1442                 kill_on_drop: true,
1443             };
1444             let _ = guard.poll_unpin(&mut context);
1445 
1446             let mut guard = ChildDropGuard {
1447                 inner: &mut mock_reaped,
1448                 kill_on_drop: true,
1449             };
1450             let _ = guard.poll_unpin(&mut context);
1451 
1452             let mut guard = ChildDropGuard {
1453                 inner: &mut mock_err,
1454                 kill_on_drop: true,
1455             };
1456             let _ = guard.poll_unpin(&mut context);
1457         }
1458 
1459         assert_eq!(1, mock_pending.num_kills);
1460         assert_eq!(1, mock_pending.num_polls);
1461 
1462         assert_eq!(0, mock_reaped.num_kills);
1463         assert_eq!(1, mock_reaped.num_polls);
1464 
1465         assert_eq!(1, mock_err.num_kills);
1466         assert_eq!(1, mock_err.num_polls);
1467     }
1468 }
1469