Auto merge of #38866 - alexcrichton:try-wait, r=aturon
std: Add a nonblocking `Child::try_wait` method This commit adds a new method to the `Child` type in the `std::process` module called `try_wait`. This method is the same as `wait` except that it will not block the calling thread and instead only attempt to collect the exit status. On Unix this means that we call `waitpid` with the `WNOHANG` flag and on Windows it just means that we pass a 0 timeout to `WaitForSingleObject`. Currently it's possible to build this method out of tree, but it's unfortunately tricky to do so. Specifically on Unix you essentially lose ownership of the pid for the process once a call to `waitpid` has succeeded. Although `Child` tracks this state internally to be resilient to multiple calls to `wait` or a `kill` after a successful wait, if the child is waited on externally then the state inside of `Child` is not updated. This means that external implementations of this method must be extra careful to essentially not use a `Child`'s methods after a call to `waitpid` has succeeded (even in a nonblocking fashion). By adding this functionality to the standard library it should help canonicalize these external implementations and ensure they can continue to robustly reuse the `Child` type from the standard library without worrying about pid ownership.
This commit is contained in:
commit
7aab3d38a0
5 changed files with 140 additions and 0 deletions
|
@ -800,6 +800,48 @@ impl Child {
|
|||
self.handle.wait().map(ExitStatus)
|
||||
}
|
||||
|
||||
/// Attempts to collect the exit status of the child if it has already
|
||||
/// exited.
|
||||
///
|
||||
/// This function will not block the calling thread and will only advisorily
|
||||
/// check to see if the child process has exited or not. If the child has
|
||||
/// exited then on Unix the process id is reaped. This function is
|
||||
/// guaranteed to repeatedly return a successful exit status so long as the
|
||||
/// child has already exited.
|
||||
///
|
||||
/// If the child has exited, then `Ok(status)` is returned. If the exit
|
||||
/// status is not available at this time then an error is returned with the
|
||||
/// error kind `WouldBlock`. If an error occurs, then that error is returned.
|
||||
///
|
||||
/// Note that unlike `wait`, this function will not attempt to drop stdin.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(process_try_wait)]
|
||||
///
|
||||
/// use std::io;
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// let mut child = Command::new("ls").spawn().unwrap();
|
||||
///
|
||||
/// match child.try_wait() {
|
||||
/// Ok(status) => println!("exited with: {}", status),
|
||||
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
/// println!("status not ready yet, let's really wait");
|
||||
/// let res = child.wait();
|
||||
/// println!("result: {:?}", res);
|
||||
/// }
|
||||
/// Err(e) => println!("error attempting to wait: {}", e),
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "process_try_wait", issue = "38903")]
|
||||
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
|
||||
self.handle.try_wait().map(ExitStatus)
|
||||
}
|
||||
|
||||
/// Simultaneously waits for the child to exit and collect all remaining
|
||||
/// output on the stdout/stderr handles, returning an `Output`
|
||||
/// instance.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue