Skip to content

Commit f689f65

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#96723
2 parents 77030b7 + 5368ea7 commit f689f65

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

library/std/src/os/windows/process.rs

+14
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,17 @@ impl CommandExt for process::Command {
180180
self
181181
}
182182
}
183+
184+
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
185+
pub trait ChildExt: Sealed {
186+
/// Extracts the main thread raw handle, without taking ownership
187+
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
188+
fn main_thread_handle(&self) -> BorrowedHandle<'_>;
189+
}
190+
191+
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
192+
impl ChildExt for process::Child {
193+
fn main_thread_handle(&self) -> BorrowedHandle<'_> {
194+
self.handle.main_thread_handle()
195+
}
196+
}

library/std/src/sys/windows/process.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::io::{self, Error, ErrorKind};
1414
use crate::mem;
1515
use crate::num::NonZeroI32;
1616
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
17-
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
17+
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
1818
use crate::path::{Path, PathBuf};
1919
use crate::ptr;
2020
use crate::sys::args::{self, Arg};
@@ -334,13 +334,14 @@ impl Command {
334334
))
335335
}?;
336336

337-
// We close the thread handle because we don't care about keeping
338-
// the thread id valid, and we aren't keeping the thread handle
339-
// around to be able to close it later.
340337
unsafe {
341-
drop(Handle::from_raw_handle(pi.hThread));
342-
343-
Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes))
338+
Ok((
339+
Process {
340+
handle: Handle::from_raw_handle(pi.hProcess),
341+
main_thread_handle: Handle::from_raw_handle(pi.hThread),
342+
},
343+
pipes,
344+
))
344345
}
345346
}
346347
}
@@ -609,6 +610,7 @@ impl From<File> for Stdio {
609610
/// for the process to terminate.
610611
pub struct Process {
611612
handle: Handle,
613+
main_thread_handle: Handle,
612614
}
613615

614616
impl Process {
@@ -621,6 +623,10 @@ impl Process {
621623
unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
622624
}
623625

626+
pub fn main_thread_handle(&self) -> BorrowedHandle<'_> {
627+
self.main_thread_handle.as_handle()
628+
}
629+
624630
pub fn wait(&mut self) -> io::Result<ExitStatus> {
625631
unsafe {
626632
let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);

library/std/src/sys/windows/process/tests.rs

+25
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@ fn test_raw_args() {
2424
);
2525
}
2626

27+
#[test]
28+
fn test_thread_handle() {
29+
use crate::os::windows::io::BorrowedHandle;
30+
use crate::os::windows::process::{ChildExt, CommandExt};
31+
const CREATE_SUSPENDED: u32 = 0x00000004;
32+
33+
let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
34+
assert!(p.is_ok());
35+
let mut p = p.unwrap();
36+
37+
extern "system" {
38+
fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
39+
}
40+
unsafe {
41+
ResumeThread(p.main_thread_handle());
42+
}
43+
44+
crate::thread::sleep(crate::time::Duration::from_millis(100));
45+
46+
let res = p.try_wait();
47+
assert!(res.is_ok());
48+
assert!(res.unwrap().is_some());
49+
assert!(p.try_wait().unwrap().unwrap().success());
50+
}
51+
2752
#[test]
2853
fn test_make_command_line() {
2954
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {

0 commit comments

Comments
 (0)