Skip to main content

Crate aligned_vmem

Crate aligned_vmem 

Source
Expand description

aligned-vmem — cross-platform aligned anonymous virtual memory.

Reserve a span of size bytes whose base is aligned to an arbitrary power-of-two align, commit/decommit its pages, and release it — directly through the OS (mmap/munmap/madvise on Unix, VirtualAlloc/ VirtualFree on Windows), with no file-mapping machinery and no dependencies. Under miri it falls back to std::alloc so consumers stay miri-testable. A consumer that installs itself as #[global_allocator] cannot use this crate under miri, because the miri backend routes allocations through the global allocator and would create a reentrancy hazard (the same class of issue numa-shim hit in #777).

This is the OS aperture extracted from sefer-alloc. It is the one crate whose entire purpose is the unsafe OS calls — every unsafe block carries a // SAFETY: proof, and a safe API is exposed on top.

§Why not region / memmap2 / mmap-rs?

Those crates are oriented around file mappings and page-protection. aligned-vmem does one different thing: hand you an anonymous span whose base is aligned to a power of two you choose (e.g. 2 MiB / 4 MiB for an allocator’s segments). On 32-bit Unix, first tries an ordinary exact-size mmap and checks whether the kernel happened to place it at an align-aligned address (fast path; hit rate depends on the OS’s placement heuristics, not on any hint this crate passes); on a miss (wrong alignment), over-reserves size + align bytes and keeps the full mapping. On 64-bit Unix, the exact-size fast path is compiled out entirely (see the module-level “bench-internals” section below and reserve_aligned’s own rustdoc), with ONE exception: on Linux AND Android, with the huge-pages feature on, a request for align == LINUX_HUGE_PAGE_SIZE (2 MiB) huge pages takes an exact-size MAP_HUGETLB attempt first, which when it succeeds reserves exactly size. The exception’s gate is any(target_os = "linux", target_os = "android") + feature = "huge-pages" — it is NOT keyed on pointer width, which is why it survives on 64-bit; and it covers Android too, so do not describe it as Linux-only. When that exception does not apply, a 64-bit Unix reservation over-reserves size + align bytes in one mmap call. On Windows, uses one syscall (fast path for align <= 64 KiB, over-reserving nothing — base == region) or two syscalls (over-reserving size + align and keeping the full mapping). The Reservation::reservation_ptr / reservation_len fields expose the full reservation; Reservation::as_ptr / len expose the aligned usable span, plus page-granularity decommit/recommit so you can hint the OS to return physical memory while keeping the address-space reservation (on Linux, Android, and Windows this is guaranteed to return physical backing; on the Darwin family — macOS/iOS/tvOS/watchOS — and the BSDs, this reclaim is advisory-only and provides no zero-fill guarantee, see decommit’s Darwin caveat). If you are building an allocator, an arena, or a slab and need “give me a 4 MiB-aligned 4 MiB span”, this is the small focused tool.

§Fallible vs infallible API (0.2)

Every reservation/commit entry point has two forms:

For most of these pairs the infallible form forwards to the try_* form and discards the cause, so both stay in perfect lockstep. The decommit family is the exception, in the OPPOSITE direction: decommit and try_decommit are siblings, not a forward/wrap pair — both call the same per-OS backend directly (each discarding or keeping its own copy of the outcome), rather than one calling the other. decommit’s contract is deliberately silent on OS-level outcome (best-effort by nature; see decommit’s own rustdoc) — it discards the backend’s answer. try_decommit’s outer Result still reports range-contract validity only (unchanged) — but since task #1180 its Ok payload is a DecommitOutcome (Skipped / Advised / Refused), which DOES observe what the SELECTED BACKEND did with a well-formed, non-empty range: whether a call was issued at all, and if so, whether it was accepted or refused. Advised names what the call did, not necessarily a real OS syscall — under the native backend it means the kernel accepted a real madvise(2)/VirtualFree call; under the aligned_vmem_mock cfg or miri, no syscall runs at all and Advised is the simulated backend’s own unconditional answer (see DecommitOutcome::Advised’s own doc for the full three-way split). Before task #1180 this was a bare Ok(()), indistinguishable from every other well-formed outcome.

§Example

use aligned_vmem::{reserve_aligned, release};

// Reserve 4 MiB aligned to 4 MiB.
let span = 4 * 1024 * 1024;
let r = reserve_aligned(span, span).expect("OOM");
let base = r.as_ptr();
assert_eq!(base.addr() % span, 0); // base is `span`-aligned

// SAFETY: `base` is valid for `r.len()` bytes; we own it exclusively.
unsafe { base.write(0xAB); assert_eq!(base.read(), 0xAB); }

// RAII release on drop, or take the parts for manual self-hosted release:
let (raw, raw_len, raw_align) = r.into_parts();
// SAFETY: the triple came from `into_parts` and is released exactly once.
unsafe { release(raw, raw_len, raw_align) };

Runnable form: tests/smoke.rs.

§Alignment contract

align must be a power of two and at least PAGE. size must be a non-zero multiple of PAGE (so decommit ranges land on page boundaries). Violations return None / Err(VmemError::invalid_argument()) rather than panicking.

§Page size (page_size)

PAGE (4 KiB) is the crate’s minimum decommit granularity — the validation constant. page_size returns the actual OS page size queried once via sysconf(_SC_PAGESIZE) (Unix) / GetSystemInfo (Windows). On Apple Silicon macOS this is 16 KiB; callers computing decommit offsets must round to page_size(), not PAGE. The crate’s own validation of both range endpoints against page_size() is the load-bearing guard: do not rely on the OS to reject a misaligned range — Linux madvise(2) rejects only a misaligned ADDRESS and rounds a misaligned LENGTH up past the requested range, and Windows VirtualFree(MEM_DECOMMIT) rejects nothing (it widens the range in both directions to whole pages). In the never-observed case where the one-time OS query fails, the crate fails closed rather than guessing — see page_size’s “If the one-time OS query fails” paragraph and try_page_size.

Re-exports§

pub use error::VmemError;

Modules§

error
VmemError — the failure cause carried by the try_* API.
fault_injectionfault-injection
Real-path commit fault injection (feature fault-injection).

Structs§

LazyReservationlazy-commit
A Reservation that also tracks how much of itself is committed.
Reservation
An owning handle to one aligned span of anonymous virtual memory.
ReservationFullParts
The full components returned by Reservation::into_full_parts.
ReservationParts
The components returned by Reservation::into_reservation_parts.

Enums§

DecommitOutcome
The observed result of one try_decommit / Reservation::try_decommit call — task #1180 (PUB-R2 phase 2), replacing the pre-#1180 Result<(), VmemError> return, which reported only whether the CALLER’S ARGUMENTS were valid, never what the OS actually did (or was even asked to do).

Constants§

MIN_PAGE
Alias for PAGE under a name that doesn’t imply “the OS page size”.
PAGE
The minimum page size this crate assumes for decommit/recommit granularity: 4 KiB, the smallest unit both mmap and VirtualAlloc will commit/decommit on the platforms this crate targets.

Functions§

commit_rangelazy-commit
Commit pages [base + start, base + end) within an existing reservation.
decommit
Decommit pages [base + start, base + end): hint the OS to return their physical backing while keeping the address-space reservation alive.
decommit_lazy
Lazy decommit variant: hint the OS it MAY reclaim [base+start, base+end) under memory pressure, cheaper than decommit (Linux MADV_FREE, macOS/iOS MADV_FREE_REUSABLE, FreeBSD/DragonFly MADV_FREE, NetBSD/OpenBSD MADV_FREE, other Unix (including tvOS/watchOS) falls back to MADV_DONTNEED; Windows falls back to the eager decommit path, which has no lazy equivalent).
lazy_commit_is_honoredlazy-commit
Whether this platform’s backend actually HONORS the initial_commit argument of reserve_aligned_lazy — i.e. whether “lazy” is real here.
leak_zeroed_pages
Reserve size bytes of zero-initialised anonymous virtual memory and leak it for the process lifetime, returning the base pointer.
page_size
Return the OS page size in bytes, querying the OS once and caching the result.
recommit
Recommit pages [base + start, base + end) previously passed to decommit. On Windows this re-commits physical pages (VirtualAlloc(MEM_COMMIT)); on Unix re-access is implicit so this is a no-op. On the Darwin family (macOS/iOS/tvOS/watchOS) specifically, whether re-access reads back zeroed pages or the pre-decommit contents is not guaranteed either way — see decommit’s Darwin caveat for why.
release
Release a whole OS reservation obtained from Reservation::into_parts.
release_parts
Release a reservation obtained from Reservation::into_reservation_parts.
reserve_aligned
Reserve size bytes of anonymous virtual memory whose base is aligned to align.
reserve_aligned_hugehuge-pages
Reserve size bytes aligned to align, requesting OS large / huge pages (Linux/Android MAP_HUGETLB, Windows MEM_LARGE_PAGES). Currently a no-op on macOS and other Unix that is neither Linux nor Android — it falls back to an ordinary reservation, identical to reserve_aligned.
reserve_aligned_lazylazy-commit
Reserve size bytes of anonymous virtual memory whose base is aligned to align, committing ONLY the first initial_commit bytes — the rest is reserved but NOT committed (on Windows; on Unix/miri ALL pages are committed, matching the eager path).
try_commit_rangelazy-commit
Fallible commit_range: Ok(()) on success (or was a well-formed no-op), Err(VmemError::invalid_argument()) if the offsets violated the contract (misaligned, or start > end), Err(VmemError) carrying the OS cause on genuine commit failure.
try_decommit
Fallible decommit: the same operation, with a channel for the one thing decommit cannot report — and, since task #1180 (PUB-R2 phase 2), a channel for the OS’s own accept/refuse answer too, not just argument validity.
try_page_size
Fallible page_size: the same cached one-time OS page-size query, with a channel for the one thing page_size cannot report — the query itself having failed.
try_recommit
Fallible recommit: Ok(()) if the range is now committed (or was a well-formed no-op), Err(VmemError::invalid_argument()) if the offsets violated the contract (misaligned, or start > end), Err(VmemError) carrying the OS cause on genuine commit failure.
try_reserve_aligned
Fallible reserve_aligned: returns a VmemError carrying the OS cause (errno / GetLastError) on failure instead of a bare None.
try_reserve_aligned_hugehuge-pages
Fallible reserve_aligned_huge.
try_reserve_aligned_lazylazy-commit
Fallible reserve_aligned_lazy.