diff --git a/dynamic-memory-api-0 b/dynamic-memory-api-0 index 4d5f71d..c60ffac 160000 --- a/dynamic-memory-api-0 +++ b/dynamic-memory-api-0 @@ -1 +1 @@ -Subproject commit 4d5f71df4bf191255cfcf1f5ae82d8b8c2183aa9 +Subproject commit c60ffac4f647d876144bbd92cbada5fb4b648afa diff --git a/src/api.rs b/src/api.rs index 6e49d22..b5bc9c2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,17 +1,21 @@ use crate::reservation::WindowsReservation; 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}; pub struct WindowsVirtualMemoryApi { pageSize: usize, + allocationGranularity: usize, totalReservationsOwned: AtomicUsize, } impl WindowsVirtualMemoryApi { pub fn startScope() -> Self { + let si = winapi_wrappers::getSystemInfo(); return Self { - pageSize: winapi_wrappers::getPageSize(), + pageSize: si.pageSize, + allocationGranularity: max(si.allocationGranularity, si.pageSize), 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 { @@ -40,12 +48,22 @@ unsafe impl VirtualMemoryApi for WindowsVirtualMemoryApi { return self.pageSize; } - fn reserveMemory<'s>( + fn reserveMemory<'s>(&'s self, pagesCount: usize) -> Option> { + 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, - extend: ReservationToExtend<&Self::Reservation<'s>>, + base: &Self::Reservation<'s>, pagesCount: usize, - ) -> Option> { - return WindowsReservation::tryReserve(self, extend, pagesCount); + ) -> ExtendResult> { + return WindowsReservation::tryReserve(self, Some(base), self.roundUpPages(pagesCount)); } } diff --git a/src/reservation.rs b/src/reservation.rs index 56af34c..fc4803a 100644 --- a/src/reservation.rs +++ b/src/reservation.rs @@ -1,5 +1,7 @@ -use crate::{winapi_wrappers, WindowsVirtualMemoryApi}; -use dynamic_memory_api_0::virtual_memory::{Reservation, ReservationToExtend, VirtualMemoryApi}; +use crate::{WindowsVirtualMemoryApi, winapi_wrappers}; +use dynamic_memory_api_0::virtual_memory::{ + ExtendResult, Reservation, VirtualMemoryApi, +}; use std::cmp::Ordering; use std::ffi::c_void; use std::mem::ManuallyDrop; @@ -16,16 +18,10 @@ pub struct WindowsReservation<'s> { impl<'s> WindowsReservation<'s> { pub(super) fn tryReserve( owner: &'s WindowsVirtualMemoryApi, - extend: ReservationToExtend<&WindowsReservation<'s>>, + extend: Option<&WindowsReservation<'s>>, pagesCount: usize, - ) -> Option { - let start: Option>; - match extend { - ReservationToExtend::ReserveAnywhere => start = None, - ReservationToExtend::TryExtend(prev) => unsafe { - start = Some(prev._offset(prev.pagesCount)) - }, - }; + ) -> ExtendResult { + let start: Option> = extend.map(|pg| unsafe { pg._offset(pg.pagesCount) }); let ptr_o; unsafe { @@ -34,8 +30,11 @@ impl<'s> WindowsReservation<'s> { let ptr; match ptr_o { - None => return None, - Some(ptr_nn) => ptr = unsafe { NonNull::new_unchecked(ptr_nn.as_ptr()) }, + ExtendResult::OutOfMemory => return ExtendResult::OutOfMemory, + ExtendResult::ContinuationIsBusy => return ExtendResult::ContinuationIsBusy, + ExtendResult::Success(ptr_nn) => { + ptr = unsafe { NonNull::new_unchecked(ptr_nn.as_ptr()) } + } } owner.changeReservationsCount(1); @@ -46,7 +45,7 @@ impl<'s> WindowsReservation<'s> { pagesCount: pagesCount, }; - return Some(reservation); + return ExtendResult::Success(reservation); } unsafe fn _offset(&self, index: usize) -> NonNull { @@ -72,8 +71,8 @@ impl<'s> WindowsReservation<'s> { } unsafe fn _release(&mut self) { - winapi_wrappers::release(self.start, self._size(0, self.pagesCount)); self.owner.changeReservationsCount(-1); + winapi_wrappers::release(self.start); } } @@ -97,18 +96,15 @@ impl PartialOrd 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<'_> { + 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] { self._assertBounds(indexOfFirst, count); let start = self._offset(indexOfFirst); @@ -119,10 +115,7 @@ unsafe impl Reservation for WindowsReservation<'_> { unsafe fn decommitPages(&mut self, indexOfFirst: usize, count: usize) { self._assertBounds(indexOfFirst, count); - winapi_wrappers::decommit( - self._offset(indexOfFirst), - self._size(indexOfFirst, count), - ) + winapi_wrappers::decommit(self._offset(indexOfFirst), self._size(indexOfFirst, count)) } unsafe fn release(mut self) { @@ -130,3 +123,14 @@ unsafe impl Reservation for WindowsReservation<'_> { 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"); + } + } +} diff --git a/src/winapi_wrappers.rs b/src/winapi_wrappers.rs index cb183f4..397c6e9 100644 --- a/src/winapi_wrappers.rs +++ b/src/winapi_wrappers.rs @@ -1,8 +1,8 @@ -use std::cmp::max; +use dynamic_memory_api_0::virtual_memory::ExtendResult; use std::ffi::c_void; use std::ptr::{NonNull, null_mut}; 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::{ 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( start: Option>, size: usize, -) -> Option> { +) -> ExtendResult> { let raw = VirtualAlloc( start.map(|p| p.as_ptr() as *const c_void), size, @@ -22,15 +22,13 @@ pub(super) unsafe fn reserve( ); if raw == null_mut::() { match GetLastError() { - ERROR_NOT_ENOUGH_MEMORY => return None, - ERROR_INVALID_ADDRESS => { - panic!("Requested address already in use (ERROR_INVALID_ADDRESS)") - } + ERROR_NOT_ENOUGH_MEMORY => return ExtendResult::OutOfMemory, + ERROR_INVALID_ADDRESS => return ExtendResult::ContinuationIsBusy, 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, size: usize) { @@ -63,8 +61,8 @@ pub(super) unsafe fn decommit(start: NonNull, size: usize) { }; } -pub(super) unsafe fn release(start: NonNull, size: usize) { - let result = VirtualFree(start.as_ptr(), size, MEM_RELEASE); +pub(super) unsafe fn release(start: NonNull) { + let result = VirtualFree(start.as_ptr(), 0, MEM_RELEASE); if result.is_err() { match GetLastError() { @@ -78,10 +76,18 @@ pub(super) unsafe fn release(start: NonNull, 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(); unsafe { 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, + }; }