//! libc syscalls supporting `rustix::mm`. #[cfg(not(target_os = "redox"))] use super::types::Advice; #[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 { syscall! { fn userfaultfd( flags: c::c_int ) via SYS_userfaultfd -> c::c_int } ret_owned_fd(userfaultfd(bitflags_bits!(flags))) }