use nix::libc::ucontext_t;
use std::os::fd::OwnedFd;
#[allow(unused_macros)]
macro_rules! bits_set {
($val:expr, $($bit:expr),+ $(,)?) => {{
let mask: u64 = 0 $(| (1 << $bit))+;
(u64::from($val) & mask) == mask
}};
}
#[allow(unused_macros)]
macro_rules! not_bits_set {
($val:expr, $($bit:expr),+ $(,)?) => {{
let mask: u64 = 0 $(| (1 << $bit))+;
(u64::from($val) & mask) == 0
}};
}
#[inline]
pub fn check_page_fault_rw_flag_from_context(ctx: ucontext_t) -> u8 {
#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "macos")))]
let flag = {
let mut val = 1;
#[cfg(target_os = "macos")]
let i = unsafe { *((*ctx.uc_mcontext).__ss.__pc as *const u32) };
#[cfg(target_os = "linux")]
let i = unsafe { *((ctx.uc_mcontext).pc as *const u32) };
if bits_set!(i, 27) && not_bits_set!(i, 25) {
if bits_set!(i, 29, 28) {
if bits_set!(i, 24) ||
(not_bits_set!(i, 24) && bits_set!(i, 21, 10)) ||
(not_bits_set!(i, 24, 10) && bits_set!(i, 21, 11)) ||
not_bits_set!(i, 24, 21)
{
if bits_set!(i, 26) {
if bits_set!(i, 22) {
val = 0;
}
} else {
if !not_bits_set!(i, 23, 22) {
val = 0;
}
}
}
}
}
val
};
#[cfg(all(target_arch = "aarch64", not(any(target_os = "linux", target_os = "macos"))))]
let flag = 1;
#[cfg(all(target_arch = "x86_64", any(target_os = "linux", target_os = "netbsd")))]
let flag = ((ctx.uc_mcontext.gregs[nix::libc::REG_ERR as usize] & 0x2) >> 1) as u8;
#[cfg(all(target_arch = "x86_64", target_os = "freebsd"))]
let flag = ((ctx.uc_mcontext.mc_err & 0x2) >> 1) as u8;
#[cfg(all(
target_arch = "x86_64",
not(any(target_os = "freebsd", target_os = "linux", target_os = "netbsd"))
))]
let flag = 1;
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
let flag = 1;
return flag;
}
#[inline]
pub fn get_shared_memory() -> Result<OwnedFd, crate::Error> {
#[cfg(target_os = "linux")]
match nix::sys::memfd::memfd_create(c"userspace-paging", nix::sys::memfd::MFdFlags::empty()) {
Ok(fd) => Ok(fd),
Err(e) => Err(crate::Error::UnixError(e)),
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
let mut failed = 0;
let mut result = None;
loop {
if failed > 10 {
break;
}
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
use rand::distr::{Alphanumeric, SampleString};
let name = format!("/usp-{}", Alphanumeric.sample_string(&mut rand::rng(), 16));
if let Ok(fd) = nix::sys::mman::shm_open(
&*name,
OFlag::O_RDWR | OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_NOFOLLOW,
Mode::S_IRUSR | Mode::S_IWUSR,
) {
result = Some(fd);
break;
}
failed += 1;
}
match result {
None => return Err(crate::Error::Unsupported),
Some(fd) => return Ok(fd),
}
};
}