rustix/backend/libc/mm/
syscalls.rs

1//! libc syscalls supporting `rustix::mm`.
2
3#[cfg(not(target_os = "redox"))]
4use super::types::Advice;
5#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
6use super::types::MlockAllFlags;
7#[cfg(any(target_os = "emscripten", target_os = "linux"))]
8use super::types::MremapFlags;
9use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags};
10#[cfg(linux_kernel)]
11use super::types::{MlockFlags, UserfaultfdFlags};
12use crate::backend::c;
13#[cfg(linux_kernel)]
14use crate::backend::conv::ret_owned_fd;
15use crate::backend::conv::{borrowed_fd, no_fd, ret};
16use crate::fd::BorrowedFd;
17#[cfg(linux_kernel)]
18use crate::fd::OwnedFd;
19use crate::io;
20
21#[cfg(not(target_os = "redox"))]
22pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> {
23    // On Linux platforms, `MADV_DONTNEED` has the same value as
24    // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different
25    // value, and check for it here.
26    #[cfg(target_os = "linux")]
27    if let Advice::LinuxDontNeed = advice {
28        return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) };
29    }
30
31    #[cfg(not(target_os = "android"))]
32    {
33        let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) };
34
35        // `posix_madvise` returns its error status rather than using `errno`.
36        if err == 0 {
37            Ok(())
38        } else {
39            Err(io::Errno(err))
40        }
41    }
42
43    #[cfg(target_os = "android")]
44    {
45        if let Advice::DontNeed = advice {
46            // Do nothing. Linux's `MADV_DONTNEED` isn't the same as
47            // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`.
48            Ok(())
49        } else {
50            unsafe { ret(c::madvise(addr, len, advice as c::c_int)) }
51        }
52    }
53}
54
55pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> {
56    let err = c::msync(addr, len, bitflags_bits!(flags));
57
58    // `msync` returns its error status rather than using `errno`.
59    if err == 0 {
60        Ok(())
61    } else {
62        Err(io::Errno(err))
63    }
64}
65
66/// # Safety
67///
68/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
69/// with memory pointed to by raw pointers is unsafe.
70pub(crate) unsafe fn mmap(
71    ptr: *mut c::c_void,
72    len: usize,
73    prot: ProtFlags,
74    flags: MapFlags,
75    fd: BorrowedFd<'_>,
76    offset: u64,
77) -> io::Result<*mut c::c_void> {
78    let res = c::mmap(
79        ptr,
80        len,
81        bitflags_bits!(prot),
82        bitflags_bits!(flags),
83        borrowed_fd(fd),
84        offset as i64,
85    );
86    if res == c::MAP_FAILED {
87        Err(io::Errno::last_os_error())
88    } else {
89        Ok(res)
90    }
91}
92
93/// # Safety
94///
95/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
96/// with memory pointed to by raw pointers is unsafe.
97pub(crate) unsafe fn mmap_anonymous(
98    ptr: *mut c::c_void,
99    len: usize,
100    prot: ProtFlags,
101    flags: MapFlags,
102) -> io::Result<*mut c::c_void> {
103    let res = c::mmap(
104        ptr,
105        len,
106        bitflags_bits!(prot),
107        bitflags_bits!(flags | MapFlags::from_bits_retain(bitcast!(c::MAP_ANONYMOUS))),
108        no_fd(),
109        0,
110    );
111    if res == c::MAP_FAILED {
112        Err(io::Errno::last_os_error())
113    } else {
114        Ok(res)
115    }
116}
117
118pub(crate) unsafe fn mprotect(
119    ptr: *mut c::c_void,
120    len: usize,
121    flags: MprotectFlags,
122) -> io::Result<()> {
123    ret(c::mprotect(ptr, len, bitflags_bits!(flags)))
124}
125
126pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> {
127    ret(c::munmap(ptr, len))
128}
129
130/// # Safety
131///
132/// `mremap` is primarily unsafe due to the `old_address` parameter, as
133/// anything working with memory pointed to by raw pointers is unsafe.
134#[cfg(any(target_os = "emscripten", target_os = "linux"))]
135pub(crate) unsafe fn mremap(
136    old_address: *mut c::c_void,
137    old_size: usize,
138    new_size: usize,
139    flags: MremapFlags,
140) -> io::Result<*mut c::c_void> {
141    let res = c::mremap(old_address, old_size, new_size, bitflags_bits!(flags));
142    if res == c::MAP_FAILED {
143        Err(io::Errno::last_os_error())
144    } else {
145        Ok(res)
146    }
147}
148
149/// # Safety
150///
151/// `mremap_fixed` is primarily unsafe due to the `old_address` and
152/// `new_address` parameters, as anything working with memory pointed to by raw
153/// pointers is unsafe.
154#[cfg(any(target_os = "emscripten", target_os = "linux"))]
155pub(crate) unsafe fn mremap_fixed(
156    old_address: *mut c::c_void,
157    old_size: usize,
158    new_size: usize,
159    flags: MremapFlags,
160    new_address: *mut c::c_void,
161) -> io::Result<*mut c::c_void> {
162    let res = c::mremap(
163        old_address,
164        old_size,
165        new_size,
166        bitflags_bits!(flags | MremapFlags::from_bits_retain(bitcast!(c::MAP_FIXED))),
167        new_address,
168    );
169    if res == c::MAP_FAILED {
170        Err(io::Errno::last_os_error())
171    } else {
172        Ok(res)
173    }
174}
175
176/// # Safety
177///
178/// `mlock` operates on raw pointers and may round out to the nearest page
179/// boundaries.
180#[inline]
181pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
182    ret(c::mlock(addr, length))
183}
184
185/// # Safety
186///
187/// `mlock_with` operates on raw pointers and may round out to the nearest page
188/// boundaries.
189#[cfg(linux_kernel)]
190#[inline]
191pub(crate) unsafe fn mlock_with(
192    addr: *mut c::c_void,
193    length: usize,
194    flags: MlockFlags,
195) -> io::Result<()> {
196    weak_or_syscall! {
197        fn mlock2(
198            addr: *const c::c_void,
199            len: c::size_t,
200            flags: c::c_int
201        ) via SYS_mlock2 -> c::c_int
202    }
203
204    ret(mlock2(addr, length, bitflags_bits!(flags)))
205}
206
207/// # Safety
208///
209/// `munlock` operates on raw pointers and may round out to the nearest page
210/// boundaries.
211#[inline]
212pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
213    ret(c::munlock(addr, length))
214}
215
216#[cfg(linux_kernel)]
217pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> {
218    syscall! {
219        fn userfaultfd(
220            flags: c::c_int
221        ) via SYS_userfaultfd -> c::c_int
222    }
223    ret_owned_fd(userfaultfd(bitflags_bits!(flags)))
224}
225
226/// Locks all pages mapped into the address space of the calling process.
227///
228/// This includes the pages of the code, data, and stack segment, as well as
229/// shared libraries, user space kernel data, shared memory, and memory-mapped
230/// files. All mapped pages are guaranteed to be resident in RAM when the call
231/// returns successfully; the pages are guaranteed to stay in RAM until later
232/// unlocked.
233#[inline]
234#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
235pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
236    unsafe { ret(c::mlockall(bitflags_bits!(flags))) }
237}
238
239/// Unlocks all pages mapped into the address space of the calling process.
240#[inline]
241#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
242pub(crate) fn munlockall() -> io::Result<()> {
243    unsafe { ret(c::munlockall()) }
244}