aligned_vmem/api/reserve_aligned_lazy.rs
1use crate::error::VmemError;
2use crate::lazy_reservation::LazyReservation;
3#[cfg(aligned_vmem_mock)]
4use crate::mock;
5#[cfg(not(aligned_vmem_mock))]
6use crate::os::reserve_aligned_lazy_raw;
7#[cfg(aligned_vmem_mock)]
8use crate::os::reserve_aligned_raw;
9
10use super::internal::{
11 finish_reservation, validate_initial_commit, validate_size_align, RawReservation,
12};
13
14/// Reserve `size` bytes of anonymous virtual memory whose base is aligned to
15/// `align`, committing ONLY the first `initial_commit` bytes — the rest is
16/// reserved but NOT committed (on Windows; on Unix/miri ALL pages are committed,
17/// matching the eager path).
18///
19/// See [`reserve_aligned`](crate::api::reserve_aligned) for the base/align contract. `initial_commit` must
20/// be a non-zero multiple of the runtime [`page_size()`](crate::page_size::page_size) (not the compile-time
21/// [`PAGE`](crate::page::PAGE)) and `<= size`; `size` must also be a multiple of [`page_size()`](crate::page_size::page_size).
22/// Violations return `None`. This stricter contract exists because on Windows,
23/// `VirtualAlloc(MEM_COMMIT)` operates on whole runtime pages and
24/// `commit_range` accepts only offsets that are multiples of `page_size()`; a
25/// `size` not aligned to `page_size()` would create an unwritable tail that
26/// cannot be committed via the public API.
27///
28/// The returned [`LazyReservation`](crate::LazyReservation) frees the ENTIRE VA
29/// reservation on drop regardless of how much was committed. (Until task #1118
30/// this sentence named `Reservation` — the wrong type. This function has
31/// returned `Option<LazyReservation>` since task #1051 introduced the
32/// watermark-owning wrapper; the reviewer who found it noted that a
33/// publication-readiness wave spent three commits resealing exactly this type
34/// without reading its own entry point's rustdoc.) For the failure cause use
35/// [`try_reserve_aligned_lazy`].
36#[must_use]
37#[cfg(feature = "lazy-commit")]
38#[cfg_attr(docsrs, doc(cfg(feature = "lazy-commit")))]
39pub fn reserve_aligned_lazy(
40 size: usize,
41 align: usize,
42 initial_commit: usize,
43) -> Option<LazyReservation> {
44 try_reserve_aligned_lazy(size, align, initial_commit).ok()
45}
46
47/// Fallible [`reserve_aligned_lazy`].
48///
49/// Returns a [`LazyReservation`], which carries the commit watermark alongside
50/// the span. Callers that keep their own commit bookkeeping take
51/// [`LazyReservation::into_reservation`] and drive the raw primitives directly.
52#[cfg(feature = "lazy-commit")]
53#[cfg_attr(docsrs, doc(cfg(feature = "lazy-commit")))]
54pub fn try_reserve_aligned_lazy(
55 size: usize,
56 align: usize,
57 initial_commit: usize,
58) -> Result<LazyReservation, VmemError> {
59 validate_size_align(size, align)?;
60 validate_initial_commit(initial_commit, size)?;
61 #[cfg(aligned_vmem_mock)]
62 if let Some(e) = mock::take_reserve_fault() {
63 mock::record(mock::Call::ReserveLazy {
64 size,
65 align,
66 initial_commit,
67 });
68 return Err(e);
69 }
70 #[cfg(aligned_vmem_mock)]
71 mock::record(mock::Call::ReserveLazy {
72 size,
73 align,
74 initial_commit,
75 });
76
77 // Under `mock` the OS partial-commit is bypassed: `commit_range` records-
78 // and-returns without touching the OS, so a genuinely partially-committed
79 // Windows reservation would leave the tail unwritable and fault when the
80 // consumer's mocked "commit" is a no-op. Chain to the EAGER (fully
81 // committed) backend instead, so the returned span is entirely usable while
82 // the mock still records the `ReserveLazy` call for assertion.
83 #[cfg(aligned_vmem_mock)]
84 let raw = reserve_aligned_raw(size, align);
85 #[cfg(not(aligned_vmem_mock))]
86 let raw = reserve_aligned_lazy_raw(size, align, initial_commit);
87
88 // task #713: both `raw` branches now capture their own `VmemError`
89 // immediately at the point of failure; this just propagates it.
90 finish_reservation(
91 size,
92 align,
93 raw.map(|(base, reservation, reservation_len)| RawReservation {
94 base,
95 reservation,
96 reservation_len,
97 granted_huge: false,
98 }),
99 )
100 .map(|r| LazyReservation::new(r, initial_commit))
101}