244 lines
6.8 KiB
Rust
244 lines
6.8 KiB
Rust
//! libc syscalls supporting `rustix::mm`.
|
|
|
|
#[cfg(not(target_os = "redox"))]
|
|
use super::types::Advice;
|
|
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
|
|
use super::types::MlockAllFlags;
|
|
#[cfg(any(target_os = "emscripten", target_os = "linux"))]
|
|
use super::types::MremapFlags;
|
|
use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags};
|
|
#[cfg(linux_kernel)]
|
|
use super::types::{MlockFlags, UserfaultfdFlags};
|
|
use crate::backend::c;
|
|
#[cfg(linux_kernel)]
|
|
use crate::backend::conv::ret_owned_fd;
|
|
use crate::backend::conv::{borrowed_fd, no_fd, ret};
|
|
use crate::fd::BorrowedFd;
|
|
#[cfg(linux_kernel)]
|
|
use crate::fd::OwnedFd;
|
|
use crate::io;
|
|
|
|
#[cfg(not(target_os = "redox"))]
|
|
pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> {
|
|
// On Linux platforms, `MADV_DONTNEED` has the same value as
|
|
// `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different
|
|
// value, and check for it here.
|
|
#[cfg(target_os = "linux")]
|
|
if let Advice::LinuxDontNeed = advice {
|
|
return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) };
|
|
}
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
{
|
|
let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) };
|
|
|
|
// `posix_madvise` returns its error status rather than using `errno`.
|
|
if err == 0 {
|
|
Ok(())
|
|
} else {
|
|
Err(io::Errno(err))
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "android")]
|
|
{
|
|
if let Advice::DontNeed = advice {
|
|
// Do nothing. Linux's `MADV_DONTNEED` isn't the same as
|
|
// `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`.
|
|
Ok(())
|
|
} else {
|
|
unsafe { ret(c::madvise(addr, len, advice as c::c_int)) }
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> {
|
|
let err = c::msync(addr, len, bitflags_bits!(flags));
|
|
|
|
// `msync` returns its error status rather than using `errno`.
|
|
if err == 0 {
|
|
Ok(())
|
|
} else {
|
|
Err(io::Errno(err))
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
|
|
/// with memory pointed to by raw pointers is unsafe.
|
|
pub(crate) unsafe fn mmap(
|
|
ptr: *mut c::c_void,
|
|
len: usize,
|
|
prot: ProtFlags,
|
|
flags: MapFlags,
|
|
fd: BorrowedFd<'_>,
|
|
offset: u64,
|
|
) -> io::Result<*mut c::c_void> {
|
|
let res = c::mmap(
|
|
ptr,
|
|
len,
|
|
bitflags_bits!(prot),
|
|
bitflags_bits!(flags),
|
|
borrowed_fd(fd),
|
|
offset as i64,
|
|
);
|
|
if res == c::MAP_FAILED {
|
|
Err(io::Errno::last_os_error())
|
|
} else {
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
|
|
/// with memory pointed to by raw pointers is unsafe.
|
|
pub(crate) unsafe fn mmap_anonymous(
|
|
ptr: *mut c::c_void,
|
|
len: usize,
|
|
prot: ProtFlags,
|
|
flags: MapFlags,
|
|
) -> io::Result<*mut c::c_void> {
|
|
let res = c::mmap(
|
|
ptr,
|
|
len,
|
|
bitflags_bits!(prot),
|
|
bitflags_bits!(flags | MapFlags::from_bits_retain(bitcast!(c::MAP_ANONYMOUS))),
|
|
no_fd(),
|
|
0,
|
|
);
|
|
if res == c::MAP_FAILED {
|
|
Err(io::Errno::last_os_error())
|
|
} else {
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
pub(crate) unsafe fn mprotect(
|
|
ptr: *mut c::c_void,
|
|
len: usize,
|
|
flags: MprotectFlags,
|
|
) -> io::Result<()> {
|
|
ret(c::mprotect(ptr, len, bitflags_bits!(flags)))
|
|
}
|
|
|
|
pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> {
|
|
ret(c::munmap(ptr, len))
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mremap` is primarily unsafe due to the `old_address` parameter, as
|
|
/// anything working with memory pointed to by raw pointers is unsafe.
|
|
#[cfg(any(target_os = "emscripten", target_os = "linux"))]
|
|
pub(crate) unsafe fn mremap(
|
|
old_address: *mut c::c_void,
|
|
old_size: usize,
|
|
new_size: usize,
|
|
flags: MremapFlags,
|
|
) -> io::Result<*mut c::c_void> {
|
|
let res = c::mremap(old_address, old_size, new_size, bitflags_bits!(flags));
|
|
if res == c::MAP_FAILED {
|
|
Err(io::Errno::last_os_error())
|
|
} else {
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mremap_fixed` is primarily unsafe due to the `old_address` and
|
|
/// `new_address` parameters, as anything working with memory pointed to by raw
|
|
/// pointers is unsafe.
|
|
#[cfg(any(target_os = "emscripten", target_os = "linux"))]
|
|
pub(crate) unsafe fn mremap_fixed(
|
|
old_address: *mut c::c_void,
|
|
old_size: usize,
|
|
new_size: usize,
|
|
flags: MremapFlags,
|
|
new_address: *mut c::c_void,
|
|
) -> io::Result<*mut c::c_void> {
|
|
let res = c::mremap(
|
|
old_address,
|
|
old_size,
|
|
new_size,
|
|
bitflags_bits!(flags | MremapFlags::from_bits_retain(bitcast!(c::MAP_FIXED))),
|
|
new_address,
|
|
);
|
|
if res == c::MAP_FAILED {
|
|
Err(io::Errno::last_os_error())
|
|
} else {
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mlock` operates on raw pointers and may round out to the nearest page
|
|
/// boundaries.
|
|
#[inline]
|
|
pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
|
|
ret(c::mlock(addr, length))
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `mlock_with` operates on raw pointers and may round out to the nearest page
|
|
/// boundaries.
|
|
#[cfg(linux_kernel)]
|
|
#[inline]
|
|
pub(crate) unsafe fn mlock_with(
|
|
addr: *mut c::c_void,
|
|
length: usize,
|
|
flags: MlockFlags,
|
|
) -> io::Result<()> {
|
|
weak_or_syscall! {
|
|
fn mlock2(
|
|
addr: *const c::c_void,
|
|
len: c::size_t,
|
|
flags: c::c_int
|
|
) via SYS_mlock2 -> c::c_int
|
|
}
|
|
|
|
ret(mlock2(addr, length, bitflags_bits!(flags)))
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `munlock` operates on raw pointers and may round out to the nearest page
|
|
/// boundaries.
|
|
#[inline]
|
|
pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
|
|
ret(c::munlock(addr, length))
|
|
}
|
|
|
|
#[cfg(linux_kernel)]
|
|
pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> {
|
|
syscall! {
|
|
fn userfaultfd(
|
|
flags: c::c_int
|
|
) via SYS_userfaultfd -> c::c_int
|
|
}
|
|
ret_owned_fd(userfaultfd(bitflags_bits!(flags)))
|
|
}
|
|
|
|
/// Locks all pages mapped into the address space of the calling process.
|
|
///
|
|
/// This includes the pages of the code, data, and stack segment, as well as
|
|
/// shared libraries, user space kernel data, shared memory, and memory-mapped
|
|
/// files. All mapped pages are guaranteed to be resident in RAM when the call
|
|
/// returns successfully; the pages are guaranteed to stay in RAM until later
|
|
/// unlocked.
|
|
#[inline]
|
|
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
|
|
pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
|
|
unsafe { ret(c::mlockall(bitflags_bits!(flags))) }
|
|
}
|
|
|
|
/// Unlocks all pages mapped into the address space of the calling process.
|
|
#[inline]
|
|
#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
|
|
pub(crate) fn munlockall() -> io::Result<()> {
|
|
unsafe { ret(c::munlockall()) }
|
|
}
|