#[cfg(unix)]
use std::ffi::CString;
#[cfg(unix)]
use std::fs::OpenOptions;
#[cfg(unix)]
use std::io::{Error, ErrorKind, Result};
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(unix)]
use std::path::Path;
#[cfg(unix)]
use std::ptr::NonNull;
#[cfg(unix)]
use std::sync::Arc;
#[cfg(unix)]
use crate::reader::{UltraSlayer, SpinPolicy};
#[cfg(unix)]
fn shm_file_path(name: &str) -> Result<std::fs::File> {
let path = Path::new("/dev/shm").join(name);
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)?;
Ok(file)
}
#[cfg(unix)]
pub struct ShmSlab<T> {
ptr: NonNull<T>,
len: usize,
_file: std::fs::File,
slayer: UltraSlayer<T>,
}
#[cfg(unix)]
impl<T> ShmSlab<T>
where
T: Copy + Send + Sync + 'static,
{
pub fn create(name: &str, channels: usize, size_bytes: usize) -> Result<Self> {
let file = shm_file_path(name)?;
file.set_len(size_bytes as u64)?;
let prot = libc::PROT_READ | libc::PROT_WRITE;
let flags = libc::MAP_SHARED
| libc::MAP_LOCKED
| libc::MAP_POPULATE
| libc::MAP_HUGETLB;
let raw_ptr = unsafe {
libc::mmap(
std::ptr::null_mut(),
size_bytes,
prot,
flags,
file.as_raw_fd(),
0,
)
};
if raw_ptr == libc::MAP_FAILED {
return Err(Error::last_os_error());
}
let ptr = NonNull::new(raw_ptr as *mut T).ok_or_else(|| {
Error::new(ErrorKind::Other, "mmap returned a null pointer")
})?;
let slayer = UltraSlayer::<T>::new(channels, size_bytes / std::mem::size_of::<T>());
Ok(Self {
ptr,
len: size_bytes / std::mem::size_of::<T>(),
_file: file,
slayer,
})
}
pub fn open(name: &str, channels: usize, size_bytes: usize) -> Result<Self> {
let file = shm_file_path(name)?;
let raw_ptr = unsafe {
libc::mmap(
std::ptr::null_mut(),
size_bytes,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
file.as_raw_fd(),
0,
)
};
if raw_ptr == libc::MAP_FAILED {
return Err(Error::last_os_error());
}
let ptr = NonNull::new(raw_ptr as *mut T).ok_or_else(|| {
Error::new(ErrorKind::Other, "mmap returned a null pointer")
})?;
let slayer = UltraSlayer::<T>::new(channels, size_bytes / std::mem::size_of::<T>());
Ok(Self {
ptr,
len: size_bytes / std::mem::size_of::<T>(),
_file: file,
slayer,
})
}
pub fn into_ultraslayer(self) -> UltraSlayer<T> {
self.slayer
}
#[inline(always)]
pub fn read(&self, idx: usize) -> T {
self.slayer.read(idx)
}
#[inline(always)]
pub fn write(&self, idx: usize, val: T) {
self.slayer.insert(idx, val);
}
#[inline(always)]
pub fn set_spin_policy(&self, policy: SpinPolicy) {
self.slayer.set_spin_policy(policy);
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
}
#[cfg(unix)]
impl<T> Drop for ShmSlab<T> {
fn drop(&mut self) {
let size_bytes = self.len * std::mem::size_of::<T>();
unsafe {
libc::munmap(self.ptr.as_ptr() as *mut _, size_bytes);
}
}
}