about summary refs log tree commit diff
diff options
context:
space:
mode:
authorunknown <abramlujan@gmail.com>2022-05-10 02:41:19 -0300
committerunknown <abramlujan@gmail.com>2022-05-10 02:41:19 -0300
commit5368ea7d2eae4e86c1c7a68197506d062bc1689d (patch)
tree57e63729d7bae198d015857768da064b886364e4
parent0dd7e10282aaa7a3e1f5660f8bb043ee4ea07355 (diff)
downloadrust-5368ea7d2eae4e86c1c7a68197506d062bc1689d.tar.gz
rust-5368ea7d2eae4e86c1c7a68197506d062bc1689d.zip
Expose process main_thread_handle on Windows
-rw-r--r--library/std/src/os/windows/process.rs14
-rw-r--r--library/std/src/sys/windows/process.rs20
-rw-r--r--library/std/src/sys/windows/process/tests.rs25
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(