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