Skip to content

Commit

Permalink
Rollup merge of rust-lang#96725 - nico-abram:win_tid, r=ChrisDenton
Browse files Browse the repository at this point in the history
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
  • Loading branch information
JohnTitor authored May 10, 2022
2 parents 77030b7 + 5368ea7 commit f689f65
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
14 changes: 14 additions & 0 deletions library/std/src/os/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
20 changes: 13 additions & 7 deletions library/std/src/sys/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
))
}
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions library/std/src/sys/windows/process/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
Expand Down

0 comments on commit f689f65

Please sign in to comment.