Skip to main content

sys_alloc/
unix.rs

1use std::io::{self, Error};
2use std::ptr;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5#[cfg(any(target_os = "linux", target_os = "android"))]
6const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE;
7
8#[cfg(not(any(target_os = "linux", target_os = "android")))]
9const MAP_POPULATE: libc::c_int = 0;
10
11#[cfg(any(
12    target_os = "linux",
13    target_os = "android",
14    target_vendor = "apple",
15    target_os = "netbsd",
16    target_os = "solaris",
17    target_os = "illumos",
18))]
19const MAP_NORESERVE: libc::c_int = libc::MAP_NORESERVE;
20
21#[cfg(not(any(
22    target_os = "linux",
23    target_os = "android",
24    target_vendor = "apple",
25    target_os = "netbsd",
26    target_os = "solaris",
27    target_os = "illumos",
28)))]
29const MAP_NORESERVE: libc::c_int = 0;
30
31/// Returns the system page size, cached atomically.
32pub fn page_size() -> usize {
33    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
34
35    match PAGE_SIZE.load(Ordering::Relaxed) {
36        0 => {
37            #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
38            let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
39            PAGE_SIZE.store(page_size, Ordering::Relaxed);
40            page_size
41        }
42        page_size => page_size,
43    }
44}
45
46pub struct MmapInner {
47    ptr: *mut libc::c_void,
48    len: usize,
49}
50
51impl MmapInner {
52    /// Creates a new anonymous memory mapping with an optional address hint.
53    ///
54    /// # Safety
55    ///
56    /// This function is unsafe because it calls `mmap`.
57    pub unsafe fn map_anon(
58        hint_addr: usize,
59        len: usize,
60        populate: bool,
61        no_reserve: bool,
62    ) -> io::Result<Self> {
63        let populate = if populate { MAP_POPULATE } else { 0 };
64        let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 };
65
66        let addr = if hint_addr == 0 {
67            ptr::null_mut()
68        } else {
69            hint_addr as *mut libc::c_void
70        };
71
72        // Standard flags for anonymous mapping
73        let flags = libc::MAP_PRIVATE | libc::MAP_ANON | populate | no_reserve;
74        let prot = libc::PROT_READ | libc::PROT_WRITE;
75
76        let ptr = unsafe { libc::mmap(addr, len, prot, flags, -1, 0) };
77
78        if ptr == libc::MAP_FAILED {
79            return Err(Error::last_os_error());
80        }
81
82        // Basic verification: if we gave a hint, did we get it?
83        // Note: we don't enforce strictness here (returning error if mismatch),
84        // that is up to the higher level policy.
85        // But for Address Space Coloring, the caller needs to check `ptr`.
86
87        Ok(Self { ptr, len })
88    }
89
90    pub const fn ptr(&self) -> *mut u8 {
91        self.ptr.cast::<u8>()
92    }
93
94    pub const fn len(&self) -> usize {
95        self.len
96    }
97
98    /// Creates a `MmapInner` from a raw pointer and length.
99    pub const unsafe fn from_raw(ptr: *mut u8, len: usize) -> Self {
100        Self {
101            ptr: ptr.cast::<libc::c_void>(),
102            len,
103        }
104    }
105}
106
107impl Drop for MmapInner {
108    fn drop(&mut self) {
109        if self.len > 0 {
110            unsafe {
111                libc::munmap(self.ptr, self.len);
112            }
113        }
114    }
115}
116
117unsafe impl Send for MmapInner {}
118unsafe impl Sync for MmapInner {}