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:
- the historical infallible form returning
Option/bool(reserve_aligned,recommit, …), and - a
try_*form returningResult<_, VmemError>whose error carries the OSerrno/GetLastErrorcause (try_reserve_aligned,try_recommit, …).
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 thetry_*API.- fault_
injection fault-injection - Real-path commit fault injection (feature
fault-injection).
Structs§
- Lazy
Reservation lazy-commit - A
Reservationthat also tracks how much of itself is committed. - Reservation
- An owning handle to one aligned span of anonymous virtual memory.
- Reservation
Full Parts - The full components returned by
Reservation::into_full_parts. - Reservation
Parts - The components returned by
Reservation::into_reservation_parts.
Enums§
- Decommit
Outcome - The observed result of one
try_decommit/Reservation::try_decommitcall — task #1180 (PUB-R2 phase 2), replacing the pre-#1180Result<(), 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
PAGEunder 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
mmapandVirtualAllocwill commit/decommit on the platforms this crate targets.
Functions§
- commit_
range ⚠lazy-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 thandecommit(LinuxMADV_FREE, macOS/iOSMADV_FREE_REUSABLE, FreeBSD/DragonFlyMADV_FREE, NetBSD/OpenBSDMADV_FREE, other Unix (including tvOS/watchOS) falls back toMADV_DONTNEED; Windows falls back to the eagerdecommitpath, which has no lazy equivalent). - lazy_
commit_ is_ honored lazy-commit - Whether this platform’s backend actually HONORS the
initial_commitargument ofreserve_aligned_lazy— i.e. whether “lazy” is real here. - leak_
zeroed_ pages - Reserve
sizebytes 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 todecommit. 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 — seedecommit’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
sizebytes of anonymous virtual memory whose base is aligned toalign. - reserve_
aligned_ huge huge-pages - Reserve
sizebytes aligned toalign, requesting OS large / huge pages (Linux/AndroidMAP_HUGETLB, WindowsMEM_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 toreserve_aligned. - reserve_
aligned_ lazy lazy-commit - Reserve
sizebytes of anonymous virtual memory whose base is aligned toalign, committing ONLY the firstinitial_commitbytes — the rest is reserved but NOT committed (on Windows; on Unix/miri ALL pages are committed, matching the eager path). - try_
commit_ ⚠range lazy-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, orstart > end),Err(VmemError)carrying the OS cause on genuine commit failure. - try_
decommit ⚠ - Fallible
decommit: the same operation, with a channel for the one thingdecommitcannot 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 thingpage_sizecannot 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, orstart > end),Err(VmemError)carrying the OS cause on genuine commit failure. - try_
reserve_ aligned - Fallible
reserve_aligned: returns aVmemErrorcarrying the OS cause (errno/GetLastError) on failure instead of a bareNone. - try_
reserve_ aligned_ huge huge-pages - Fallible
reserve_aligned_huge. - try_
reserve_ aligned_ lazy lazy-commit - Fallible
reserve_aligned_lazy.