mod builder;
mod crash;
cfg_if::cfg_if! {
if #[cfg(feature = "semaphore")] {
mod semaphore;
pub use semaphore::{Semaphore, SemaphorePermission, SemaphoreSettings};
}
}
pub use builder::CortexBuilder;
pub use crash::CortexError;
pub type CortexResult<T> = std::result::Result<T, CortexError>;
fn try_clear_mem(id: i32) -> CortexResult<()> {
unsafe {
if libc::shmctl(id, libc::IPC_RMID, std::ptr::null_mut()) == -1 {
return Err(CortexError::new_dirty(format!(
"Error cleaning up shared memory with id: {}",
id
)));
}
}
Ok(())
}
pub trait CortexSync: Sized {
type Settings;
fn new(cortex_key: i32, settings: Option<&Self::Settings>) -> CortexResult<Self>;
fn attach(cortex_key: i32) -> CortexResult<Self>;
fn read_lock(&self) -> CortexResult<()>;
fn write_lock(&self) -> CortexResult<()>;
fn release(&self) -> CortexResult<()>;
}
#[derive(Debug)]
pub struct Cortex<T, L> {
key: i32,
id: i32,
#[allow(dead_code)]
size: usize,
is_owner: bool,
lock: L,
ptr: *mut T,
}
impl<T, L: CortexSync> Cortex<T, L> {
pub fn new(key: i32, data: T, lock_settings: Option<&L::Settings>) -> CortexResult<Self> {
let lock = L::new(key, lock_settings)?;
let size = std::mem::size_of::<T>();
let permissions = libc::IPC_CREAT | libc::IPC_EXCL | 0o666;
let id = unsafe { libc::shmget(key, size, permissions) };
if id == -1 {
try_clear_mem(id)?
} else {
tracing::trace!("Allocated {} bytes with id {}", size, id);
}
let ptr = unsafe { libc::shmat(id, std::ptr::null_mut(), 0) as *mut T };
if ptr as isize == -1 {
try_clear_mem(id)?;
} else {
tracing::trace!("Successfully attached shared memory");
}
unsafe {
ptr.write(data);
}
Ok(Self {
id,
key,
size,
is_owner: true,
lock,
ptr,
})
}
pub fn attach(key: i32) -> CortexResult<Self> {
let lock = L::attach(key)?;
let id = unsafe {
libc::shmget(key, 0, 0o666) };
if id == -1 {
return Err(CortexError::new_clean(format!(
"Error during shmget for key {}",
key,
)));
} else {
tracing::trace!("Found shared memory with id {}", id);
}
let ptr = unsafe { libc::shmat(id, std::ptr::null_mut(), 0) as *mut T };
if ptr as isize == -1 {
return Err(CortexError::new_clean("Error during shmat"));
} else {
tracing::trace!("Successfully attached shared memory");
}
Ok(Self {
id,
key,
size: std::mem::size_of::<T>(),
is_owner: false,
lock,
ptr,
})
}
pub fn read(&self) -> CortexResult<T> {
unsafe {
self.lock.read_lock()?;
let data = self.ptr.read();
self.lock.release()?;
Ok(data)
}
}
pub fn write(&self, data: T) -> CortexResult<()> {
unsafe {
self.lock.write_lock()?;
self.ptr.write(data);
self.lock.release()?;
}
Ok(())
}
pub fn key(&self) -> i32 {
self.key
}
}
impl<T, L> Drop for Cortex<T, L> {
fn drop(&mut self) {
if !self.is_owner {
return;
}
if let Err(err) = try_clear_mem(self.id) {
tracing::error!("Error during Drop: {}", err)
}
}
}