use crate::{crash::CortexError, CortexResult, CortexSync};
use std::ffi::CString;
fn get_name(shmem_key: i32) -> CortexResult<CString> {
let name = CString::new(format!("cortex_semaphore_{}", shmem_key))?;
Ok(name)
}
#[allow(dead_code)]
pub enum SemaphorePermission {
OwnerOnly,
OwnerAndGroup,
ReadWriteForOthers,
ReadOnlyForOthers,
FullAccessForEveryone,
Custom(libc::mode_t),
}
impl SemaphorePermission {
fn into_mode(self) -> libc::mode_t {
match self {
SemaphorePermission::OwnerOnly => libc::S_IRWXU,
SemaphorePermission::OwnerAndGroup => libc::S_IRWXU | libc::S_IRWXG,
SemaphorePermission::ReadWriteForOthers => {
libc::S_IRWXU | libc::S_IRWXG | libc::S_IROTH | libc::S_IWOTH
}
SemaphorePermission::ReadOnlyForOthers => libc::S_IRWXU | libc::S_IRWXG | libc::S_IROTH,
SemaphorePermission::FullAccessForEveryone => {
libc::S_IRWXU | libc::S_IRWXG | libc::S_IROTH | libc::S_IWOTH | libc::S_IXOTH
}
SemaphorePermission::Custom(mode) => mode,
}
}
}
pub struct Semaphore {
semaphore: *mut libc::sem_t,
name: CString,
is_owner: bool,
}
pub struct SemaphoreSettings {
pub mode: SemaphorePermission,
}
impl Drop for Semaphore {
fn drop(&mut self) {
if !self.is_owner {
return;
}
unsafe {
if libc::sem_close(self.semaphore) == -1 {
tracing::error!("Error during sem_close");
};
if libc::sem_unlink(self.name.as_ptr()) == -1 {
tracing::error!("Error during sem_unlink");
}
}
}
}
impl CortexSync for Semaphore {
type Settings = SemaphoreSettings;
fn new(shmem_key: i32, settings: Option<Self::Settings>) -> CortexResult<Self> {
let permission = if let Some(settings) = settings {
settings.mode
} else {
SemaphorePermission::OwnerOnly
};
let name = get_name(shmem_key)?;
let name_ptr = name.as_ptr();
let semaphore = unsafe {
libc::sem_open(
name_ptr,
libc::O_EXCL | libc::O_CREAT,
permission.into_mode(),
1,
)
};
if semaphore == libc::SEM_FAILED {
return Err(CortexError::new_clean("Error during sem_open"));
}
Ok(Self {
semaphore,
name,
is_owner: true,
})
}
fn attach(shmem_key: i32) -> CortexResult<Self> {
let name = get_name(shmem_key)?;
let name_ptr = name.as_ptr();
let semaphore = unsafe { libc::sem_open(name_ptr, 0, 0, 0) };
if semaphore == libc::SEM_FAILED {
return Err(CortexError::new_clean("Error during sem_open"));
}
Ok(Self {
semaphore,
name,
is_owner: false,
})
}
fn read_lock(&self) {
unsafe {
libc::sem_wait(self.semaphore);
}
}
fn write_lock(&self) {
unsafe {
libc::sem_wait(self.semaphore);
}
}
fn release(&self) {
unsafe {
libc::sem_post(self.semaphore);
}
}
}