Fixes and verbose reporting about re-reserving same region

This commit is contained in:
Andrew Golovashevich 2025-12-19 02:10:37 +03:00
parent 6ca1d4e306
commit d1c1f411fa
4 changed files with 77 additions and 49 deletions

@ -1 +1 @@
Subproject commit 4d5f71df4bf191255cfcf1f5ae82d8b8c2183aa9 Subproject commit c60ffac4f647d876144bbd92cbada5fb4b648afa

View File

@ -1,17 +1,21 @@
use crate::reservation::WindowsReservation; use crate::reservation::WindowsReservation;
use crate::winapi_wrappers; use crate::winapi_wrappers;
use dynamic_memory_api_0::virtual_memory::{ReservationToExtend, VirtualMemoryApi}; use dynamic_memory_api_0::virtual_memory::{ExtendResult, VirtualMemoryApi};
use std::cmp::max;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
pub struct WindowsVirtualMemoryApi { pub struct WindowsVirtualMemoryApi {
pageSize: usize, pageSize: usize,
allocationGranularity: usize,
totalReservationsOwned: AtomicUsize, totalReservationsOwned: AtomicUsize,
} }
impl WindowsVirtualMemoryApi { impl WindowsVirtualMemoryApi {
pub fn startScope() -> Self { pub fn startScope() -> Self {
let si = winapi_wrappers::getSystemInfo();
return Self { return Self {
pageSize: winapi_wrappers::getPageSize(), pageSize: si.pageSize,
allocationGranularity: max(si.allocationGranularity, si.pageSize),
totalReservationsOwned: AtomicUsize::new(0), totalReservationsOwned: AtomicUsize::new(0),
}; };
} }
@ -31,6 +35,10 @@ impl WindowsVirtualMemoryApi {
} }
} }
} }
fn roundUpPages(&self, pagesCount: usize) -> usize {
return (pagesCount * self.pageSize + (self.allocationGranularity - 1)) / self.pageSize;
}
} }
unsafe impl VirtualMemoryApi for WindowsVirtualMemoryApi { unsafe impl VirtualMemoryApi for WindowsVirtualMemoryApi {
@ -40,12 +48,22 @@ unsafe impl VirtualMemoryApi for WindowsVirtualMemoryApi {
return self.pageSize; return self.pageSize;
} }
fn reserveMemory<'s>( fn reserveMemory<'s>(&'s self, pagesCount: usize) -> Option<Self::Reservation<'s>> {
match WindowsReservation::tryReserve(self, None, self.roundUpPages(pagesCount)) {
ExtendResult::OutOfMemory => return None,
ExtendResult::ContinuationIsBusy => {
panic!("Unreachable (system reported that region is busy, but it wasn't specified)")
}
ExtendResult::Success(r) => return Some(r),
}
}
unsafe fn extendReservation<'s>(
&'s self, &'s self,
extend: ReservationToExtend<&Self::Reservation<'s>>, base: &Self::Reservation<'s>,
pagesCount: usize, pagesCount: usize,
) -> Option<Self::Reservation<'s>> { ) -> ExtendResult<WindowsReservation<'s>> {
return WindowsReservation::tryReserve(self, extend, pagesCount); return WindowsReservation::tryReserve(self, Some(base), self.roundUpPages(pagesCount));
} }
} }

View File

@ -1,5 +1,7 @@
use crate::{winapi_wrappers, WindowsVirtualMemoryApi}; use crate::{WindowsVirtualMemoryApi, winapi_wrappers};
use dynamic_memory_api_0::virtual_memory::{Reservation, ReservationToExtend, VirtualMemoryApi}; use dynamic_memory_api_0::virtual_memory::{
ExtendResult, Reservation, VirtualMemoryApi,
};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ffi::c_void; use std::ffi::c_void;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@ -16,16 +18,10 @@ pub struct WindowsReservation<'s> {
impl<'s> WindowsReservation<'s> { impl<'s> WindowsReservation<'s> {
pub(super) fn tryReserve( pub(super) fn tryReserve(
owner: &'s WindowsVirtualMemoryApi, owner: &'s WindowsVirtualMemoryApi,
extend: ReservationToExtend<&WindowsReservation<'s>>, extend: Option<&WindowsReservation<'s>>,
pagesCount: usize, pagesCount: usize,
) -> Option<Self> { ) -> ExtendResult<Self> {
let start: Option<NonNull<c_void>>; let start: Option<NonNull<c_void>> = extend.map(|pg| unsafe { pg._offset(pg.pagesCount) });
match extend {
ReservationToExtend::ReserveAnywhere => start = None,
ReservationToExtend::TryExtend(prev) => unsafe {
start = Some(prev._offset(prev.pagesCount))
},
};
let ptr_o; let ptr_o;
unsafe { unsafe {
@ -34,8 +30,11 @@ impl<'s> WindowsReservation<'s> {
let ptr; let ptr;
match ptr_o { match ptr_o {
None => return None, ExtendResult::OutOfMemory => return ExtendResult::OutOfMemory,
Some(ptr_nn) => ptr = unsafe { NonNull::new_unchecked(ptr_nn.as_ptr()) }, ExtendResult::ContinuationIsBusy => return ExtendResult::ContinuationIsBusy,
ExtendResult::Success(ptr_nn) => {
ptr = unsafe { NonNull::new_unchecked(ptr_nn.as_ptr()) }
}
} }
owner.changeReservationsCount(1); owner.changeReservationsCount(1);
@ -46,7 +45,7 @@ impl<'s> WindowsReservation<'s> {
pagesCount: pagesCount, pagesCount: pagesCount,
}; };
return Some(reservation); return ExtendResult::Success(reservation);
} }
unsafe fn _offset(&self, index: usize) -> NonNull<c_void> { unsafe fn _offset(&self, index: usize) -> NonNull<c_void> {
@ -72,8 +71,8 @@ impl<'s> WindowsReservation<'s> {
} }
unsafe fn _release(&mut self) { unsafe fn _release(&mut self) {
winapi_wrappers::release(self.start, self._size(0, self.pagesCount));
self.owner.changeReservationsCount(-1); self.owner.changeReservationsCount(-1);
winapi_wrappers::release(self.start);
} }
} }
@ -97,18 +96,15 @@ impl PartialOrd<Self> for WindowsReservation<'_> {
} }
} }
impl Drop for WindowsReservation<'_> {
fn drop(&mut self) {
unsafe {
self._release();
}
if !panicking() {
panic!("Reserved virtual memory wasn't released explicitly");
}
}
}
unsafe impl Reservation for WindowsReservation<'_> { unsafe impl Reservation for WindowsReservation<'_> {
fn getPageSize(&self) -> usize {
return self.owner.getPageSize();
}
fn pagesCount(&self) -> usize {
return self.pagesCount;
}
unsafe fn commitPages(&mut self, indexOfFirst: usize, count: usize) -> *mut [u8] { unsafe fn commitPages(&mut self, indexOfFirst: usize, count: usize) -> *mut [u8] {
self._assertBounds(indexOfFirst, count); self._assertBounds(indexOfFirst, count);
let start = self._offset(indexOfFirst); let start = self._offset(indexOfFirst);
@ -119,10 +115,7 @@ unsafe impl Reservation for WindowsReservation<'_> {
unsafe fn decommitPages(&mut self, indexOfFirst: usize, count: usize) { unsafe fn decommitPages(&mut self, indexOfFirst: usize, count: usize) {
self._assertBounds(indexOfFirst, count); self._assertBounds(indexOfFirst, count);
winapi_wrappers::decommit( winapi_wrappers::decommit(self._offset(indexOfFirst), self._size(indexOfFirst, count))
self._offset(indexOfFirst),
self._size(indexOfFirst, count),
)
} }
unsafe fn release(mut self) { unsafe fn release(mut self) {
@ -130,3 +123,14 @@ unsafe impl Reservation for WindowsReservation<'_> {
let _ = ManuallyDrop::new(self); let _ = ManuallyDrop::new(self);
} }
} }
impl Drop for WindowsReservation<'_> {
fn drop(&mut self) {
unsafe {
self._release();
}
if !panicking() {
panic!("Reserved virtual memory wasn't released explicitly");
}
}
}

View File

@ -1,8 +1,8 @@
use std::cmp::max; use dynamic_memory_api_0::virtual_memory::ExtendResult;
use std::ffi::c_void; use std::ffi::c_void;
use std::ptr::{NonNull, null_mut}; use std::ptr::{NonNull, null_mut};
use windows::Win32::Foundation::{ use windows::Win32::Foundation::{
ERROR_INVALID_ADDRESS, ERROR_NOT_ENOUGH_MEMORY, GetLastError, WIN32_ERROR, ERROR_INVALID_ADDRESS, ERROR_NOT_ENOUGH_MEMORY, GetLastError, WIN32_ERROR
}; };
use windows::Win32::System::Memory::{ use windows::Win32::System::Memory::{
MEM_COMMIT, MEM_DECOMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_NOACCESS, PAGE_READWRITE, MEM_COMMIT, MEM_DECOMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_NOACCESS, PAGE_READWRITE,
@ -13,7 +13,7 @@ use windows::Win32::System::SystemInformation::{GetSystemInfo, SYSTEM_INFO};
pub(super) unsafe fn reserve( pub(super) unsafe fn reserve(
start: Option<NonNull<c_void>>, start: Option<NonNull<c_void>>,
size: usize, size: usize,
) -> Option<NonNull<c_void>> { ) -> ExtendResult<NonNull<c_void>> {
let raw = VirtualAlloc( let raw = VirtualAlloc(
start.map(|p| p.as_ptr() as *const c_void), start.map(|p| p.as_ptr() as *const c_void),
size, size,
@ -22,15 +22,13 @@ pub(super) unsafe fn reserve(
); );
if raw == null_mut::<c_void>() { if raw == null_mut::<c_void>() {
match GetLastError() { match GetLastError() {
ERROR_NOT_ENOUGH_MEMORY => return None, ERROR_NOT_ENOUGH_MEMORY => return ExtendResult::OutOfMemory,
ERROR_INVALID_ADDRESS => { ERROR_INVALID_ADDRESS => return ExtendResult::ContinuationIsBusy,
panic!("Requested address already in use (ERROR_INVALID_ADDRESS)")
}
WIN32_ERROR(code) => panic!("Unexpected Win32 API Error: code={}", code), WIN32_ERROR(code) => panic!("Unexpected Win32 API Error: code={}", code),
} }
}; };
return NonNull::new(raw); return ExtendResult::Success(NonNull::new_unchecked(raw));
} }
pub(super) unsafe fn commit(start: NonNull<c_void>, size: usize) { pub(super) unsafe fn commit(start: NonNull<c_void>, size: usize) {
@ -63,8 +61,8 @@ pub(super) unsafe fn decommit(start: NonNull<c_void>, size: usize) {
}; };
} }
pub(super) unsafe fn release(start: NonNull<c_void>, size: usize) { pub(super) unsafe fn release(start: NonNull<c_void>) {
let result = VirtualFree(start.as_ptr(), size, MEM_RELEASE); let result = VirtualFree(start.as_ptr(), 0, MEM_RELEASE);
if result.is_err() { if result.is_err() {
match GetLastError() { match GetLastError() {
@ -78,10 +76,18 @@ pub(super) unsafe fn release(start: NonNull<c_void>, size: usize) {
}; };
} }
pub(super) fn getPageSize() -> usize { pub(super) struct SystemInfo {
pub pageSize: usize,
pub allocationGranularity: usize,
}
pub(super) fn getSystemInfo() -> SystemInfo {
let mut si = SYSTEM_INFO::default(); let mut si = SYSTEM_INFO::default();
unsafe { unsafe {
GetSystemInfo(&mut si as *mut _); GetSystemInfo(&mut si as *mut _);
} }
return max(si.dwPageSize, si.dwAllocationGranularity) as usize; return SystemInfo {
pageSize: si.dwPageSize as usize,
allocationGranularity: si.dwAllocationGranularity as usize,
};
} }