1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
//! `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](https://github.com/rust-lang/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`](https://crates.io/crates/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 returning [`Result<_, VmemError>`] whose error carries the
//! OS `errno` / `GetLastError` cause ([`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
//!
//! ```text
//! 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`].
// Under `mock` the real platform syscalls (decommit/recommit/commit_range) are
// bypassed by the recording backend, so their per-OS `*_impl` helpers become
// legitimately unused. This used to be a crate-wide `allow(dead_code)`, which
// made the whole crate structurally unable to report ANY unused item under
// `--all-features` (task #646/F8). Narrowed to per-item
// `#[cfg_attr(aligned_vmem_mock, allow(dead_code))]` on exactly the helpers
// confirmed (by building `RUSTFLAGS="--cfg aligned_vmem_mock" cargo build
// --features lazy-commit,huge-pages,fault-injection` on Windows, Unix
// (`--target x86_64-unknown-linux-gnu`) and miri (`--cfg miri`)) to go dead
// under `mock` alone: the per-OS `decommit_pages_impl` / `recommit_pages_impl`
// / `commit_range_impl` / `reserve_aligned_lazy_raw` trio-plus-one on each
// platform, plus the Windows-only `winapi_virtual_decommit` +
// `MEM_DECOMMIT` and the Unix-only `libc_madvise` + `madv_free_advice` +
// `MADV_DONTNEED` + `MADV_FREE` (all only reachable from the real decommit
// path, which `mock` bypasses).
// `fault_injection` carries two hooks with one call site each (task #1219
// added the second). The COMMIT-side hook (`should_fail_commit`) is consulted
// only from `try_commit_range`, which is itself gated on `lazy-commit`: a
// caller who enables `fault-injection` without `lazy-commit` gets a
// compiled-but-unreachable hook (harmless — the feature is additive and
// test-only); suppress dead-code only in that specific combination, on the
// single item it affects. The DECOMMIT-side hook (`should_fail_decommit`) is
// consulted only from `dispatch_try_decommit`, which is NOT feature-gated
// (decommit is core API), so its only orphaning combination is the mock cfg —
// see its own `#[cfg_attr(aligned_vmem_mock, allow(dead_code))]`.
//
// Structural alternative considered and deferred for a future major release:
// reorganize the three backends as separate `#[cfg]`-selected private modules
// (`os_windows` / `os_unix` / `os_miri`) with one shared private signature,
// allowing `mock` to be a fourth module selected by the same `#[cfg]` mechanism.
// That would eliminate every `#[cfg_attr(aligned_vmem_mock, allow(dead_code))]`
// attribute, but is a larger refactor than this crate's 0.2.0 release should
// carry. The current partial-replacement shape (mock replaces decommit/recommit/
// commit_range but not reserve/release) is explicitly chosen.
//
// Module layout (task #1055 / R7-10 / perf item 54): this file used to be one
// 4656-line monolith. It is now the crate's re-export surface only — every
// item lives in a module named after it (or, where the crate itself already
// documents two functions as one feature in two forms — an infallible/`try_*`
// pair, or a family of per-platform bench-internals counters — grouped into
// one file per that established pairing, not atomized further).
pub use VmemError;
pub use DecommitOutcome;
pub use MIN_PAGE;
pub use PAGE;
pub use page_size;
pub use try_page_size;
pub use validate_page_size;
pub use ;
pub use Reservation;
pub use lazy_commit_is_honored;
pub use LazyReservation;
pub use ReservationParts;
pub use ReservationFullParts;
pub use ;
pub use ;
pub use ;