diff options
| author | Yuki Okushi <jtitor@2k36.org> | 2022-05-11 00:09:32 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-11 00:09:32 +0900 |
| commit | f689f6582ccdbe8d1629416becb3671ecc69a7f2 (patch) | |
| tree | cf5d98f16f8012c4eaa6354e57f9ff7293571f78 | |
| parent | 77030b7825796461f10ee5dd774caa46ad09c64a (diff) | |
| parent | 5368ea7d2eae4e86c1c7a68197506d062bc1689d (diff) | |
| download | rust-f689f6582ccdbe8d1629416becb3671ecc69a7f2.tar.gz rust-f689f6582ccdbe8d1629416becb3671ecc69a7f2.zip | |
Rollup merge of #96725 - nico-abram:win_tid, r=ChrisDenton
Expose process windows_process_extensions_main_thread_handle on Windows
~~I did not find any tests in https://github.com/rust-lang/rust/blob/7d3e03666a93bd2b0f78b3933f9305832af771a5/library/std/src/sys/windows/process/tests.rs that actually launch processes, so I haven't added tests for this.~~ I ran the following locally, to check that it works as expected:
```rs
#![feature(windows_process_extensions_main_thread_handle)]
fn main() {
use std::os::windows::process::{ChildExt, CommandExt};
const CREATE_SUSPENDED: u32 = 0x00000004;
let proc = std::process::Command::new("cmd")
.args(["/C", "echo hello"])
.creation_flags(CREATE_SUSPENDED)
.spawn()
.unwrap();
extern "system" {
fn ResumeThread(_: *mut std::ffi::c_void) -> u32;
}
unsafe {
ResumeThread(proc.main_thread_handle());
}
let output = proc.wait_with_output().unwrap();
let str_output = std::str::from_utf8(&output.stdout[..]).unwrap();
println!("{}", str_output);
}
```
Without the feature attribute it wouldn't compile, and commenting the `ResumeThread` line makes it hang forever, showing that it works.
Trakcing issue https://github.com/rust-lang/rust/issues/96723
| -rw-r--r-- | library/std/src/os/windows/process.rs | 14 | ||||
| -rw-r--r-- | library/std/src/sys/windows/process.rs | 20 | ||||
| -rw-r--r-- | library/std/src/sys/windows/process/tests.rs | 25 |
3 files changed, 52 insertions, 7 deletions
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index e1896309914..1c7e361c2a4 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -180,3 +180,17 @@ impl CommandExt for process::Command { self } } + +#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] +pub trait ChildExt: Sealed { + /// Extracts the main thread raw handle, without taking ownership + #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] + fn main_thread_handle(&self) -> BorrowedHandle<'_>; +} + +#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] +impl ChildExt for process::Child { + fn main_thread_handle(&self) -> BorrowedHandle<'_> { + self.handle.main_thread_handle() + } +} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index cc29d1a72fb..476b4b21cb1 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -14,7 +14,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; -use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle}; +use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sys::args::{self, Arg}; @@ -334,13 +334,14 @@ impl Command { )) }?; - // We close the thread handle because we don't care about keeping - // the thread id valid, and we aren't keeping the thread handle - // around to be able to close it later. unsafe { - drop(Handle::from_raw_handle(pi.hThread)); - - Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes)) + Ok(( + Process { + handle: Handle::from_raw_handle(pi.hProcess), + main_thread_handle: Handle::from_raw_handle(pi.hThread), + }, + pipes, + )) } } } @@ -609,6 +610,7 @@ impl From<File> for Stdio { /// for the process to terminate. pub struct Process { handle: Handle, + main_thread_handle: Handle, } impl Process { @@ -621,6 +623,10 @@ impl Process { unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 } } + pub fn main_thread_handle(&self) -> BorrowedHandle<'_> { + self.main_thread_handle.as_handle() + } + pub fn wait(&mut self) -> io::Result<ExitStatus> { unsafe { let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE); diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index be3a0f4ed52..3fc0c75240c 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -25,6 +25,31 @@ fn test_raw_args() { } #[test] +fn test_thread_handle() { + use crate::os::windows::io::BorrowedHandle; + use crate::os::windows::process::{ChildExt, CommandExt}; + const CREATE_SUSPENDED: u32 = 0x00000004; + + let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn(); + assert!(p.is_ok()); + let mut p = p.unwrap(); + + extern "system" { + fn ResumeThread(_: BorrowedHandle<'_>) -> u32; + } + unsafe { + ResumeThread(p.main_thread_handle()); + } + + crate::thread::sleep(crate::time::Duration::from_millis(100)); + + let res = p.try_wait(); + assert!(res.is_ok()); + assert!(res.unwrap().is_some()); + assert!(p.try_wait().unwrap().unwrap().success()); +} + +#[test] fn test_make_command_line() { fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String { let command_line = &make_command_line( |
