use libc::{
c_int, close, ftruncate, mmap, mode_t, munmap, shm_open, shm_unlink, MAP_SHARED, PROT_READ,
PROT_WRITE,
};
use std::ffi::CString;
use std::os::fd::RawFd;
use std::os::raw::c_void;
use std::ptr;
use std::result::Result;
pub struct ShmHandle {
shm_fd: RawFd,
size: usize,
mapped_memory: *mut c_void,
shm_name: CString,
}
impl ShmHandle {
pub fn new(
shm_name: &str,
size: usize,
flag: c_int,
mode: mode_t,
) -> Result<Self, Box<dyn std::error::Error>> {
let shm_name_c = CString::new(shm_name)?;
let is_writer = flag & libc::O_CREAT != 0;
if is_writer {
unsafe { shm_unlink(shm_name_c.as_ptr()) };
}
let shm_fd = unsafe { shm_open(shm_name_c.as_ptr(), flag, u32::from(mode)) };
if shm_fd < 0 {
eprintln!("shm_open failed");
return Err(Box::new(std::io::Error::last_os_error()));
}
if is_writer {
if unsafe { ftruncate(shm_fd, size as i64) } == -1 {
eprintln!("ftruncate failed");
unsafe { close(shm_fd) };
return Err(Box::new(std::io::Error::last_os_error()));
}
}
let mapped_memory = unsafe {
mmap(
ptr::null_mut(),
size,
PROT_WRITE | PROT_READ,
MAP_SHARED,
shm_fd,
0,
)
};
if mapped_memory == libc::MAP_FAILED {
eprintln!("mmap failed");
unsafe { close(shm_fd) };
return Err(Box::new(std::io::Error::last_os_error()));
}
Ok(Self {
shm_fd,
size,
mapped_memory,
shm_name: shm_name_c,
})
}
pub fn as_mut_ptr_u8(&mut self) -> *mut u8 {
self.mapped_memory as *mut u8
}
}
impl Drop for ShmHandle {
fn drop(&mut self) {
eprintln!("dropping shm handle");
unsafe {
if munmap(self.mapped_memory, self.size) == -1 {
eprintln!("munmap failed");
}
if close(self.shm_fd) == -1 {
eprintln!("close failed");
}
if shm_unlink(self.shm_name.as_ptr()) == -1 {
eprintln!("shm_unlink failed");
}
}
}
}