diff --git a/crates/stdlib/src/overlapped.rs b/crates/stdlib/src/overlapped.rs index 573d1fc0c85..eb2a968c042 100644 --- a/crates/stdlib/src/overlapped.rs +++ b/crates/stdlib/src/overlapped.rs @@ -14,7 +14,7 @@ mod _overlapped { convert::{ToPyException, ToPyObject}, function::OptionalArg, protocol::PyBuffer, - types::Constructor, + types::{Constructor, Destructor}, }; use windows_sys::Win32::{ Foundation::{self, GetLastError, HANDLE}, @@ -235,14 +235,8 @@ mod _overlapped { } fn from_windows_err(err: u32, vm: &VirtualMachine) -> PyBaseExceptionRef { - use Foundation::{ERROR_CONNECTION_ABORTED, ERROR_CONNECTION_REFUSED}; debug_assert_ne!(err, 0, "call errno_err instead"); - let exc = match err { - ERROR_CONNECTION_REFUSED => vm.ctx.exceptions.connection_refused_error, - ERROR_CONNECTION_ABORTED => vm.ctx.exceptions.connection_aborted_error, - err => return std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm), - }; - vm.new_exception_empty(exc.to_owned()) + std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm) } fn HasOverlappedIoCompleted(overlapped: &OVERLAPPED) -> bool { @@ -383,7 +377,7 @@ mod _overlapped { } } - #[pyclass(with(Constructor))] + #[pyclass(with(Constructor, Destructor))] impl Overlapped { #[pygetset] fn address(&self, _vm: &VirtualMachine) -> usize { @@ -438,7 +432,6 @@ mod _overlapped { use windows_sys::Win32::Foundation::{ ERROR_BROKEN_PIPE, ERROR_IO_PENDING, ERROR_MORE_DATA, ERROR_SUCCESS, }; - use windows_sys::Win32::System::IO::GetOverlappedResult; let mut inner = zelf.inner.lock(); let wait = wait.unwrap_or(false); @@ -454,7 +447,7 @@ mod _overlapped { // Get the result let mut transferred: u32 = 0; let ret = unsafe { - GetOverlappedResult( + windows_sys::Win32::System::IO::GetOverlappedResult( inner.handle, &inner.overlapped, &mut transferred, @@ -1190,35 +1183,6 @@ mod _overlapped { } } - // ConnectPipe - this is a static method that returns a handle - #[pymethod] - fn ConnectPipe(address: String, vm: &VirtualMachine) -> PyResult { - use windows_sys::Win32::Storage::FileSystem::{ - CreateFileW, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ, FILE_GENERIC_WRITE, - OPEN_EXISTING, - }; - - let address_wide: Vec = address.encode_utf16().chain(std::iter::once(0)).collect(); - - let handle = unsafe { - CreateFileW( - address_wide.as_ptr(), - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - 0, - std::ptr::null(), - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - std::ptr::null_mut(), - ) - }; - - if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE { - return Err(vm.new_last_os_error()); - } - - Ok(handle as isize) - } - // WSASendTo #[pymethod] fn WSASendTo( @@ -1508,6 +1472,78 @@ mod _overlapped { } } + impl Destructor for Overlapped { + fn del(zelf: &Py, _vm: &VirtualMachine) -> PyResult<()> { + use windows_sys::Win32::System::IO::{CancelIoEx, GetOverlappedResult}; + + let mut inner = zelf.inner.lock(); + let olderr = unsafe { GetLastError() }; + + // Cancel pending I/O and wait for completion + if !HasOverlappedIoCompleted(&inner.overlapped) + && !matches!( + inner.data, + OverlappedData::None | OverlappedData::NotStarted + ) + { + let cancelled = unsafe { CancelIoEx(inner.handle, &inner.overlapped) } != 0; + + if cancelled { + // Wait for the cancellation to complete + let mut transferred: u32 = 0; + unsafe { + GetOverlappedResult( + inner.handle, + &inner.overlapped, + &mut transferred, + 1, // bWait = TRUE + ) + }; + } + } + + // Close the event handle + if !inner.overlapped.hEvent.is_null() { + unsafe { + Foundation::CloseHandle(inner.overlapped.hEvent); + } + inner.overlapped.hEvent = std::ptr::null_mut(); + } + + // Restore last error + unsafe { Foundation::SetLastError(olderr) }; + + Ok(()) + } + } + + #[pyfunction] + fn ConnectPipe(address: String, vm: &VirtualMachine) -> PyResult { + use windows_sys::Win32::Storage::FileSystem::{ + CreateFileW, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ, FILE_GENERIC_WRITE, OPEN_EXISTING, + }; + + let address_wide: Vec = address.encode_utf16().chain(std::iter::once(0)).collect(); + + let handle = unsafe { + CreateFileW( + address_wide.as_ptr(), + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + 0, + std::ptr::null(), + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + std::ptr::null_mut(), + ) + }; + + if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE { + return Err(vm.new_last_os_error()); + } + + Ok(handle as isize) + } + #[pyfunction] fn CreateIoCompletionPort( handle: isize, diff --git a/crates/vm/src/stdlib/winapi.rs b/crates/vm/src/stdlib/winapi.rs index 1ebb2831763..c1fe32aadfc 100644 --- a/crates/vm/src/stdlib/winapi.rs +++ b/crates/vm/src/stdlib/winapi.rs @@ -94,6 +94,7 @@ mod _winapi { SEC_LARGE_PAGES, SEC_NOCACHE, SEC_RESERVE, SEC_WRITECOMBINE, }, Pipes::{ + NMPWAIT_NOWAIT, NMPWAIT_USE_DEFAULT_WAIT, NMPWAIT_WAIT_FOREVER, PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_WAIT, }, SystemServices::LOCALE_NAME_MAX_LENGTH,