diff --git a/tokio/src/process/mod.rs b/tokio/src/process/mod.rs index 7ae503f51..42654b198 100644 --- a/tokio/src/process/mod.rs +++ b/tokio/src/process/mod.rs @@ -199,6 +199,8 @@ use std::io; #[cfg(unix)] use std::os::unix::process::CommandExt; #[cfg(windows)] +use std::os::windows::io::{AsRawHandle, RawHandle}; +#[cfg(windows)] use std::os::windows::process::CommandExt; use std::path::Path; use std::pin::Pin; @@ -952,6 +954,16 @@ impl Child { } } + /// Extracts the raw handle of the process associated with this child while + /// it is still running. Returns `None` if the child has exited. + #[cfg(windows)] + pub fn raw_handle(&self) -> Option { + match &self.child { + FusedChild::Child(c) => Some(c.inner.as_raw_handle()), + FusedChild::Done(_) => None, + } + } + /// Attempts to force the child to exit, but does not wait for the request /// to take effect. /// diff --git a/tokio/src/process/windows.rs b/tokio/src/process/windows.rs index 7237525da..06fc1b6cf 100644 --- a/tokio/src/process/windows.rs +++ b/tokio/src/process/windows.rs @@ -24,7 +24,7 @@ use mio::windows::NamedPipe; use std::fmt; use std::future::Future; use std::io; -use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle}; +use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use std::pin::Pin; use std::process::Stdio; use std::process::{Child as StdChild, Command as StdCommand, ExitStatus}; @@ -144,6 +144,12 @@ impl Future for Child { } } +impl AsRawHandle for Child { + fn as_raw_handle(&self) -> RawHandle { + self.child.as_raw_handle() + } +} + impl Drop for Waiting { fn drop(&mut self) { unsafe { diff --git a/tokio/tests/process_raw_handle.rs b/tokio/tests/process_raw_handle.rs new file mode 100644 index 000000000..727e66d65 --- /dev/null +++ b/tokio/tests/process_raw_handle.rs @@ -0,0 +1,23 @@ +#![warn(rust_2018_idioms)] +#![cfg(feature = "full")] +#![cfg(windows)] + +use tokio::process::Command; +use winapi::um::processthreadsapi::GetProcessId; + +#[tokio::test] +async fn obtain_raw_handle() { + let mut cmd = Command::new("cmd"); + cmd.kill_on_drop(true); + cmd.arg("/c"); + cmd.arg("pause"); + + let child = cmd.spawn().unwrap(); + + let orig_id = child.id().expect("missing id"); + assert!(orig_id > 0); + + let handle = child.raw_handle().expect("process stopped"); + let handled_id = unsafe { GetProcessId(handle as _) }; + assert_eq!(handled_id, orig_id); +}