Expose process main_thread_handle on Windows
This commit is contained in:
parent
0dd7e10282
commit
5368ea7d2e
3 changed files with 52 additions and 7 deletions
|
@ -180,3 +180,17 @@ impl CommandExt for 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::io::{self, Error, ErrorKind};
|
||||||
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 @@ 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 {
|
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 @@ impl From<File> for 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 @@ impl Process {
|
||||||
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…
Add table
Add a link
Reference in a new issue