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 7d3e03666a/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
This commit is contained in:
commit
f689f6582c
@ -180,3 +180,17 @@ fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command {
|
|||||||
self
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::num::NonZeroI32;
|
use crate::num::NonZeroI32;
|
||||||
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
|
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::path::{Path, PathBuf};
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
use crate::sys::args::{self, Arg};
|
use crate::sys::args::{self, Arg};
|
||||||
@ -334,13 +334,14 @@ pub fn spawn(
|
|||||||
))
|
))
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
// 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 {
|
unsafe {
|
||||||
drop(Handle::from_raw_handle(pi.hThread));
|
Ok((
|
||||||
|
Process {
|
||||||
Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes))
|
handle: Handle::from_raw_handle(pi.hProcess),
|
||||||
|
main_thread_handle: Handle::from_raw_handle(pi.hThread),
|
||||||
|
},
|
||||||
|
pipes,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,6 +610,7 @@ fn from(file: File) -> Stdio {
|
|||||||
/// for the process to terminate.
|
/// for the process to terminate.
|
||||||
pub struct Process {
|
pub struct Process {
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
|
main_thread_handle: Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
@ -621,6 +623,10 @@ pub fn id(&self) -> u32 {
|
|||||||
unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
|
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> {
|
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
|
let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
|
||||||
|
@ -24,6 +24,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]
|
#[test]
|
||||||
fn test_make_command_line() {
|
fn test_make_command_line() {
|
||||||
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
|
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user