Skip to main content

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}