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