diff --git a/src/bump_arena_lazy.rs b/src/bump_arena_lazy.rs index 156379b..ab1bd3b 100644 --- a/src/bump_arena_lazy.rs +++ b/src/bump_arena_lazy.rs @@ -55,6 +55,8 @@ use crate::{UninitAllocator, sys}; pub struct BumpArenaLazy { base: NonNull, capacity: usize, + // pays the cost of syscall upfront. + page_size: usize, offset: Cell, commit: Cell, last_os_error: Cell, @@ -96,11 +98,14 @@ impl BumpArenaLazy { /// /// [`new`]: BumpArenaLazy::new pub fn try_new(capacity: usize) -> Result { + let page_size = sys::page_size(); + // saves us one unnecessary syscall. if capacity == 0 { return Ok(Self { base: NonNull::dangling(), capacity: 0, + page_size, offset: Cell::new(0), commit: Cell::new(0), last_os_error: Cell::new(0), @@ -113,6 +118,7 @@ impl BumpArenaLazy { Ok(Self { base, capacity, + page_size, offset: Cell::new(0), commit: Cell::new(0), last_os_error: Cell::new(0), @@ -210,11 +216,10 @@ impl BumpArenaLazy { offset: usize, size: usize, ) -> Option<&mut [MaybeUninit]> { - let page = sys::page_size(); let current = self.commit.get(); // Round offset up to the next page boundary, capped by capacity. - let needed = offset.checked_next_multiple_of(page)?.min(self.capacity); + let needed = offset.checked_next_multiple_of(self.page_size)?.min(self.capacity); // Safety: // > `current` is page‑aligned and within the reservation. diff --git a/src/sys.rs b/src/sys.rs index ad75d6f..9bf0910 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -64,7 +64,6 @@ pub fn page_size() -> usize { mod platform { use core::ffi::c_void; use core::ptr::NonNull; - use core::sync::atomic::{AtomicUsize, Ordering}; unsafe extern "C" { fn mmap( @@ -162,28 +161,11 @@ mod platform { unsafe { *errno_location() } } - static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); - + #[allow(clippy::cast_sign_loss)] #[inline] pub fn page_size() -> usize { - let sz = PAGE_SIZE.load(Ordering::Relaxed); - if sz != 0 { - return sz; - } - page_size_store() - } - - #[allow( - clippy::cast_possible_truncation, - clippy::cast_sign_loss, - reason = "getpagesize returns an int, but page sizes are never negative or very large" - )] - #[cold] - fn page_size_store() -> usize { - let raw = unsafe { getpagesize() }; - let sz = if raw <= 0 { 4 * 1024 } else { raw as usize }; - PAGE_SIZE.store(sz, Ordering::Relaxed); - sz + let sz = unsafe { getpagesize() }; + if sz <= 0 { 4 * 1024 } else { sz as usize } } } @@ -191,7 +173,6 @@ mod platform { mod platform { use core::ffi::c_void; use core::ptr::NonNull; - use core::sync::atomic::{AtomicUsize, Ordering}; unsafe extern "system" { fn VirtualAlloc( @@ -248,23 +229,10 @@ mod platform { unsafe { GetLastError() }.cast_signed() } - static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); - #[inline] pub fn page_size() -> usize { - let sz = PAGE_SIZE.load(Ordering::Relaxed); - if sz != 0 { - return sz; - } - page_size_store() - } - - #[cold] - fn page_size_store() -> usize { let mut info: SYSTEM_INFO = unsafe { core::mem::zeroed() }; unsafe { GetSystemInfo(&raw mut info) }; - let sz = info.dwPageSize as usize; - PAGE_SIZE.store(sz, Ordering::Relaxed); - sz + info.dwPageSize as usize } } diff --git a/src/typed_arena_lazy.rs b/src/typed_arena_lazy.rs index 253bbeb..d45d618 100644 --- a/src/typed_arena_lazy.rs +++ b/src/typed_arena_lazy.rs @@ -39,6 +39,8 @@ use crate::sys; pub struct TypedArenaLazy { base: NonNull>, capacity: usize, + // pays the cost of syscall upfront. + page_size: usize, offset: Cell, commit: Cell, last_os_error: Cell, @@ -76,10 +78,13 @@ impl TypedArenaLazy { /// /// [`new`]: TypedArenaLazy::new pub fn try_new(capacity: usize) -> Result { + let page_size = sys::page_size(); + if capacity == 0 || size_of::() == 0 { return Ok(Self { base: NonNull::dangling(), capacity, + page_size, offset: Cell::new(0), commit: Cell::new(0), last_os_error: Cell::new(0), @@ -94,6 +99,7 @@ impl TypedArenaLazy { Ok(Self { base: base.cast(), capacity, + page_size, offset: Cell::new(0), commit: Cell::new(0), last_os_error: Cell::new(0), @@ -181,14 +187,13 @@ impl TypedArenaLazy { #[inline(never)] #[allow(clippy::mut_from_ref)] fn alloc_bump(&self, idx: usize, required_bytes: usize, value: T) -> Option<&mut T> { - let page = sys::page_size(); let current = self.commit.get(); // `new` guarantees `capacity * size_of::()` fits. let total_bytes = self.capacity * size_of::(); // Next page rounding - let needed = required_bytes.checked_next_multiple_of(page)?.min(total_bytes); + let needed = required_bytes.checked_next_multiple_of(self.page_size)?.min(total_bytes); // Safety: // > `current` is page‑aligned and within the reservation.