diff options
Diffstat (limited to 'src/process/windows.rs')
-rw-r--r-- | src/process/windows.rs | 127 |
1 files changed, 99 insertions, 28 deletions
diff --git a/src/process/windows.rs b/src/process/windows.rs index 136d5b0..0e4c7dd 100644 --- a/src/process/windows.rs +++ b/src/process/windows.rs @@ -15,29 +15,31 @@ //! `RegisterWaitForSingleObject` and then wait on the other end of the oneshot //! from then on out. -use crate::io::PollEvented; +use crate::io::{blocking::Blocking, AsyncRead, AsyncWrite, ReadBuf}; use crate::process::kill::Kill; use crate::process::SpawnedChild; use crate::sync::oneshot; -use mio::windows::NamedPipe; use std::fmt; +use std::fs::File as StdFile; use std::future::Future; use std::io; -use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use std::os::windows::prelude::{AsRawHandle, IntoRawHandle, RawHandle}; use std::pin::Pin; use std::process::Stdio; use std::process::{Child as StdChild, Command as StdCommand, ExitStatus}; -use std::ptr; -use std::task::Context; -use std::task::Poll; -use winapi::shared::minwindef::{DWORD, FALSE}; -use winapi::um::handleapi::{DuplicateHandle, INVALID_HANDLE_VALUE}; -use winapi::um::processthreadsapi::GetCurrentProcess; -use winapi::um::threadpoollegacyapiset::UnregisterWaitEx; -use winapi::um::winbase::{RegisterWaitForSingleObject, INFINITE}; -use winapi::um::winnt::{ - BOOLEAN, DUPLICATE_SAME_ACCESS, HANDLE, PVOID, WT_EXECUTEINWAITTHREAD, WT_EXECUTEONLYONCE, +use std::sync::Arc; +use std::task::{Context, Poll}; + +use windows_sys::{ + Win32::Foundation::{ + DuplicateHandle, BOOLEAN, DUPLICATE_SAME_ACCESS, HANDLE, INVALID_HANDLE_VALUE, + }, + Win32::System::Threading::{ + GetCurrentProcess, RegisterWaitForSingleObject, UnregisterWaitEx, WT_EXECUTEINWAITTHREAD, + WT_EXECUTEONLYONCE, + }, + Win32::System::WindowsProgramming::INFINITE, }; #[must_use = "futures do nothing unless polled"] @@ -119,11 +121,11 @@ impl Future for Child { } let (tx, rx) = oneshot::channel(); let ptr = Box::into_raw(Box::new(Some(tx))); - let mut wait_object = ptr::null_mut(); + let mut wait_object = 0; let rc = unsafe { RegisterWaitForSingleObject( &mut wait_object, - inner.child.as_raw_handle(), + inner.child.as_raw_handle() as _, Some(callback), ptr as *mut _, INFINITE, @@ -162,37 +164,106 @@ impl Drop for Waiting { } } -unsafe extern "system" fn callback(ptr: PVOID, _timer_fired: BOOLEAN) { +unsafe extern "system" fn callback(ptr: *mut std::ffi::c_void, _timer_fired: BOOLEAN) { let complete = &mut *(ptr as *mut Option<oneshot::Sender<()>>); let _ = complete.take().unwrap().send(()); } -pub(crate) type ChildStdio = PollEvented<NamedPipe>; +#[derive(Debug)] +struct ArcFile(Arc<StdFile>); + +impl io::Read for ArcFile { + fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> { + (&*self.0).read(bytes) + } +} + +impl io::Write for ArcFile { + fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { + (&*self.0).write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + (&*self.0).flush() + } +} + +#[derive(Debug)] +pub(crate) struct ChildStdio { + // Used for accessing the raw handle, even if the io version is busy + raw: Arc<StdFile>, + // For doing I/O operations asynchronously + io: Blocking<ArcFile>, +} + +impl AsRawHandle for ChildStdio { + fn as_raw_handle(&self) -> RawHandle { + self.raw.as_raw_handle() + } +} -pub(super) fn stdio<T>(io: T) -> io::Result<PollEvented<NamedPipe>> +impl AsyncRead for ChildStdio { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll<io::Result<()>> { + Pin::new(&mut self.io).poll_read(cx, buf) + } +} + +impl AsyncWrite for ChildStdio { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { + Pin::new(&mut self.io).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.io).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.io).poll_shutdown(cx) + } +} + +pub(super) fn stdio<T>(io: T) -> io::Result<ChildStdio> where T: IntoRawHandle, { - let pipe = unsafe { NamedPipe::from_raw_handle(io.into_raw_handle()) }; - PollEvented::new(pipe) + use std::os::windows::prelude::FromRawHandle; + + let raw = Arc::new(unsafe { StdFile::from_raw_handle(io.into_raw_handle()) }); + let io = Blocking::new(ArcFile(raw.clone())); + Ok(ChildStdio { raw, io }) +} + +pub(crate) fn convert_to_stdio(child_stdio: ChildStdio) -> io::Result<Stdio> { + let ChildStdio { raw, io } = child_stdio; + drop(io); // Try to drop the Arc count here + + Arc::try_unwrap(raw) + .or_else(|raw| duplicate_handle(&*raw)) + .map(Stdio::from) } -pub(crate) fn convert_to_stdio(io: PollEvented<NamedPipe>) -> io::Result<Stdio> { - let named_pipe = io.into_inner()?; +fn duplicate_handle<T: AsRawHandle>(io: &T) -> io::Result<StdFile> { + use std::os::windows::prelude::FromRawHandle; - // Mio does not implement `IntoRawHandle` for `NamedPipe`, so we'll manually - // duplicate the handle here... unsafe { let mut dup_handle = INVALID_HANDLE_VALUE; let cur_proc = GetCurrentProcess(); let status = DuplicateHandle( cur_proc, - named_pipe.as_raw_handle(), + io.as_raw_handle() as _, cur_proc, &mut dup_handle, - 0 as DWORD, - FALSE, + 0, + 0, DUPLICATE_SAME_ACCESS, ); @@ -200,6 +271,6 @@ pub(crate) fn convert_to_stdio(io: PollEvented<NamedPipe>) -> io::Result<Stdio> return Err(io::Error::last_os_error()); } - Ok(Stdio::from_raw_handle(dup_handle)) + Ok(StdFile::from_raw_handle(dup_handle as _)) } } |