use rustix::{
fd::{AsFd, OwnedFd},
io::Errno,
};
#[cfg(target_os = "linux")]
#[inline]
pub fn create() -> rustix::io::Result<OwnedFd> {
match memfd() {
Ok(fd) => Ok(fd),
Err(Errno::NOSYS) => fallback_shm(),
Err(err) => Err(err),
}
}
#[cfg(not(target_os = "linux"))]
#[inline]
pub fn create() -> rustix::io::Result<OwnedFd> {
fallback_shm()
}
#[inline]
fn fallback_shm() -> rustix::io::Result<OwnedFd> {
use rustix::{
path::DecInt,
shm::OFlags,
time::{ClockId, clock_gettime},
};
const PREFIX: &[u8] = b"waybackend-";
let mut write_buf = PREFIX.to_vec();
let flags = OFlags::CREATE | OFlags::EXCL | OFlags::RDWR;
let mode = rustix::shm::Mode::RUSR | rustix::shm::Mode::WUSR;
loop {
let filename = {
let time = clock_gettime(ClockId::Monotonic);
write_buf.truncate(PREFIX.len());
write_buf.extend_from_slice(DecInt::new(time.tv_sec).as_bytes());
write_buf.extend_from_slice(DecInt::new(time.tv_nsec).as_bytes());
write_buf.as_slice()
};
match rustix::shm::open(filename, flags, mode) {
Ok(fd) => return rustix::shm::unlink(filename).map(|()| fd),
Err(Errno::EXIST | Errno::INTR) => continue,
Err(err) => return Err(err),
}
}
}
#[cfg(target_os = "linux")]
#[inline]
fn memfd() -> rustix::io::Result<OwnedFd> {
use rustix::fs::MemfdFlags;
use rustix::fs::SealFlags;
const FLAGS: MemfdFlags = MemfdFlags::ALLOW_SEALING.union(MemfdFlags::CLOEXEC);
const NAME: &core::ffi::CStr = c"waybackend";
const SEALS: SealFlags = SealFlags::SHRINK.union(SealFlags::SEAL);
let fd = rustix::io::retry_on_intr(|| rustix::fs::memfd_create(NAME, FLAGS))?;
let _ = rustix::fs::fcntl_add_seals(&fd, SEALS);
Ok(fd)
}
pub struct MmappedSlice<'a>(pub &'a mut [u32]);
impl<'a> MmappedSlice<'a> {
#[inline]
pub fn new<Fd: AsFd>(fd: &'a mut Fd, len: usize, offset: u64) -> rustix::io::Result<Self> {
use rustix::mm::{MapFlags, ProtFlags};
const PROT: ProtFlags = ProtFlags::READ.union(ProtFlags::WRITE);
const FLAGS: MapFlags = MapFlags::SHARED;
let data = unsafe {
let mmap = rustix::mm::mmap(core::ptr::null_mut(), len, PROT, FLAGS, fd, offset)?;
core::slice::from_raw_parts_mut(mmap.cast(), len / core::mem::size_of::<u32>())
};
Ok(MmappedSlice(data))
}
}
impl Drop for MmappedSlice<'_> {
fn drop(&mut self) {
unsafe { rustix::mm::munmap(self.0.as_mut_ptr().cast(), core::mem::size_of_val(self.0)) }
.unwrap()
}
}