From f957f7f9a7363db3a2640b55354c38958acc9c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Saparelli?= Date: Thu, 29 Jul 2021 03:42:03 +1200 Subject: [PATCH] process: add Child::raw_handle() on windows (#3998) Fixes #3987 --- tokio/src/process/mod.rs | 12 ++++++++++++ tokio/src/process/windows.rs | 8 +++++++- tokio/tests/process_raw_handle.rs | 23 +++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tokio/tests/process_raw_handle.rs 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); +}