use crate::INVALID_FD;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ptr;
use std::slice;
pub struct POSIXShmSliced<T, const N: usize> {
file_path: String,
fd_shm: i32,
mem_size: usize,
ptr_data: *mut libc::c_void,
phantom: PhantomData<T>,
}
impl<T, const N: usize> POSIXShmSliced<T, N> {
pub fn new(path: String, size: usize) -> Self {
POSIXShmSliced {
file_path: path,
fd_shm: INVALID_FD,
mem_size: size,
ptr_data: std::ptr::null_mut(),
phantom: PhantomData,
}
}
pub unsafe fn open(&mut self) -> Result<(), String> {
let c_str = CString::new(self.file_path.to_string()).unwrap();
self.fd_shm = libc::shm_open(
c_str.as_ptr(),
libc::O_CREAT | libc::O_RDWR,
libc::S_IRUSR | libc::S_IWUSR,
);
if self.fd_shm > 0 {
let ret = libc::ftruncate(self.fd_shm, self.mem_size.try_into().unwrap());
if ret < 0 {
return Err(String::from("Cannot truncate"));
}
} else {
let e = libc::__errno_location();
return Err(String::from(format!(
"Error opening shared memory {} errno {}",
self.fd_shm, *e
)));
}
self.ptr_data = libc::mmap(
ptr::null_mut(),
self.mem_size,
libc::PROT_WRITE,
libc::MAP_SHARED,
self.fd_shm,
0,
);
if self.ptr_data.is_null() {
return Err(String::from("Error, mmap failed"));
}
Ok(())
}
pub unsafe fn read(&mut self) -> Result<&[T], String> {
if self.ptr_data.is_null() {
return Err(String::from("Error. Shared memory destination is NULL"));
}
let p = self.ptr_data as *const T;
let ret = slice::from_raw_parts(p, N);
Ok(ret)
}
pub fn get_cptr_mut(&self) -> *mut libc::c_void {
self.ptr_data
}
pub fn get_as_mut(&self) -> *mut T {
self.ptr_data as *mut T
}
pub unsafe fn close(&mut self, unlink: bool) -> Result<(), String> {
let ret = libc::munmap(self.ptr_data, self.mem_size);
if ret < 0 {
return Err(String::from("Error unmapping shared memory"));
}
let ret = libc::close(self.fd_shm);
if ret < 0 {
return Err(String::from("Error closing shared memory"));
}
if unlink {
let c_shm_name = CString::new(self.file_path.to_string()).unwrap();
let ret = libc::shm_unlink(c_shm_name.as_ptr());
if ret < 0 {
return Err(String::from("Error unlinking shared memory"));
}
}
Ok(())
}
}
#[cfg(test)]
use std::mem;
#[test]
fn test_sliced() {
unsafe {
let shm_name = "test_sliced_shared_memory_file";
const NUM_ELEMENTS: usize = 2;
const MEM_SIZE: usize = mem::size_of::<u64>() * NUM_ELEMENTS;
let mut sliced_shm =
POSIXShmSliced::<u64, NUM_ELEMENTS>::new(shm_name.to_string(), MEM_SIZE);
let ret = sliced_shm.open();
assert_eq!(ret.is_ok(), true);
let data = [1u64, 2u64];
let ptr_slice: *mut u64 = sliced_shm.get_as_mut();
for i in 0..NUM_ELEMENTS {
*ptr_slice.add(i) = data[i];
}
let ptr_sliced = sliced_shm.read();
assert_eq!(ptr_sliced.is_ok(), true);
let ptr_sliced = ptr_sliced.unwrap();
for i in 0..NUM_ELEMENTS {
assert_eq!(ptr_sliced[i], data[i]);
}
let ret = sliced_shm.close(true);
assert_eq!(ret.is_ok(), true);
}
}