use crate::{Advise, Flush, Protect};
use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::ptr;
use libc::{
c_void, madvise, mlock, mmap, mprotect, msync, munlock, munmap, off_t, sysconf, MADV_DONTNEED,
MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL, MADV_WILLNEED, MAP_ANON, MAP_FAILED, MAP_PRIVATE,
MAP_SHARED, MS_ASYNC, MS_SYNC, PROT_EXEC, PROT_READ, PROT_WRITE, _SC_PAGESIZE,
};
use crate::{Error, Operation, Result};
use self::Operation::*;
#[cfg(all(feature = "io", any(target_os = "macos", target_os = "ios")))]
mod mach;
#[cfg(all(feature = "io", any(target_os = "macos", target_os = "ios")))]
pub use self::mach::{map_ring, unmap_ring};
#[cfg(all(feature = "io", not(any(target_os = "macos", target_os = "ios"))))]
mod posix;
#[cfg(all(feature = "io", not(any(target_os = "macos", target_os = "ios"))))]
pub use self::posix::{map_ring, unmap_ring};
pub fn system_info() -> (u32, u32) {
let size = unsafe { sysconf(_SC_PAGESIZE) as u32 };
(size, size)
}
fn result(op: Operation, pg: *mut c_void) -> Result<*mut u8> {
if pg == MAP_FAILED {
Err(Error::last_os_error(op))
} else {
Ok(pg as *mut u8)
}
}
pub fn map_file(file: &File, off: usize, len: usize, prot: Protect) -> Result<*mut u8> {
let (prot, flags) = match prot {
Protect::ReadOnly => (PROT_READ, MAP_SHARED),
Protect::ReadWrite => (PROT_READ | PROT_WRITE, MAP_SHARED),
Protect::ReadCopy => (PROT_READ | PROT_WRITE, MAP_PRIVATE),
Protect::ReadExec => (PROT_READ | PROT_EXEC, MAP_PRIVATE),
};
unsafe {
result(
MapFile,
mmap(
ptr::null_mut(),
len,
prot,
flags,
file.as_raw_fd(),
off as off_t,
),
)
}
}
pub fn map_anon(len: usize, prot: Protect) -> Result<*mut u8> {
let (prot, flags) = match prot {
Protect::ReadOnly => (PROT_READ, MAP_SHARED),
Protect::ReadWrite => (PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED),
Protect::ReadCopy => (PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE),
Protect::ReadExec => (PROT_READ | PROT_EXEC, MAP_ANON | MAP_PRIVATE),
};
unsafe { result(MapAnonymous, mmap(ptr::null_mut(), len, prot, flags, -1, 0)) }
}
pub unsafe fn unmap(pg: *mut u8, len: usize) -> Result<()> {
if munmap(pg as *mut c_void, len) < 0 {
Err(Error::last_os_error(Unmap))
} else {
Ok(())
}
}
pub unsafe fn protect(pg: *mut u8, len: usize, prot: Protect) -> Result<()> {
let prot = match prot {
Protect::ReadOnly => PROT_READ,
Protect::ReadWrite => PROT_READ | PROT_WRITE,
Protect::ReadCopy => PROT_READ | PROT_WRITE,
Protect::ReadExec => PROT_READ | PROT_EXEC,
};
if mprotect(pg as *mut c_void, len, prot) != 0 {
Err(Error::last_os_error(Protect))
} else {
Ok(())
}
}
pub unsafe fn flush(pg: *mut u8, _file: &File, len: usize, mode: Flush) -> Result<()> {
let flags = match mode {
Flush::Sync => MS_SYNC,
Flush::Async => MS_ASYNC,
};
if msync(pg as *mut c_void, len, flags) < 0 {
Err(Error::last_os_error(Flush))
} else {
Ok(())
}
}
pub unsafe fn advise(pg: *mut u8, len: usize, adv: Advise) -> Result<()> {
let adv = match adv {
Advise::Normal => MADV_NORMAL,
Advise::Sequential => MADV_SEQUENTIAL,
Advise::Random => MADV_RANDOM,
Advise::WillNeed => MADV_WILLNEED,
Advise::WillNotNeed => MADV_DONTNEED,
};
if madvise(pg as *mut c_void, len, adv) < 0 {
Err(Error::last_os_error(Advise))
} else {
Ok(())
}
}
pub unsafe fn lock(pg: *mut u8, len: usize) -> Result<()> {
if mlock(pg as *mut c_void, len) < 0 {
Err(Error::last_os_error(Lock))
} else {
Ok(())
}
}
pub unsafe fn unlock(pg: *mut u8, len: usize) -> Result<()> {
if munlock(pg as *mut c_void, len) < 0 {
Err(Error::last_os_error(Unlock))
} else {
Ok(())
}
}