70122892e5
sem_open/map_named_semaphore now canonicalizes names: /mysem → sem./mysem Prevents namespace collisions with raw shm_open usage. Matches glibc's /dev/shm/sem.NAME convention.
174 lines
6.4 KiB
Diff
174 lines
6.4 KiB
Diff
diff --git a/src/header/semaphore/mod.rs b/src/header/semaphore/mod.rs
|
|
index 0ca2fa9..8a1cad4 100644
|
|
--- a/src/header/semaphore/mod.rs
|
|
+++ b/src/header/semaphore/mod.rs
|
|
@@ -2,12 +2,27 @@
|
|
//!
|
|
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
|
|
|
|
+use alloc::collections::BTreeMap;
|
|
+use alloc::vec::Vec;
|
|
+use core::ptr;
|
|
+use core::sync::atomic::{AtomicUsize, Ordering};
|
|
+
|
|
use crate::{
|
|
+ c_str::CStr,
|
|
header::{
|
|
bits_timespec::timespec,
|
|
+ errno::EINVAL,
|
|
+ fcntl::{O_CREAT, O_EXCL, O_RDWR},
|
|
+ sys_mman::{
|
|
+ MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE, mmap, munmap, shm_open, shm_unlink,
|
|
+ },
|
|
time::{CLOCK_MONOTONIC, CLOCK_REALTIME},
|
|
},
|
|
- platform::types::{c_char, c_int, c_long, c_uint, clockid_t},
|
|
+ platform::{
|
|
+ Pal, Sys, ERRNO,
|
|
+ types::{c_char, c_int, c_long, c_uint, clockid_t, mode_t},
|
|
+ },
|
|
+ sync::Mutex,
|
|
};
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
|
|
@@ -19,11 +34,87 @@ pub union sem_t {
|
|
pub align: c_long,
|
|
}
|
|
pub type RlctSempahore = crate::sync::Semaphore;
|
|
+#[repr(C)]
|
|
+struct NamedSemaphore {
|
|
+ sem: RlctSempahore,
|
|
+}
|
|
+
|
|
+const SEM_FAILED_PTR: *mut sem_t = usize::MAX as *mut sem_t;
|
|
+
|
|
+struct NamedSemEntry {
|
|
+ ptr: *mut NamedSemaphore,
|
|
+ size: usize,
|
|
+ refs: AtomicUsize,
|
|
+ unlinked: bool,
|
|
+}
|
|
+unsafe impl Send for NamedSemEntry {}
|
|
+
|
|
+static NAMED_SEMS: Mutex<Option<BTreeMap<Vec<u8>, NamedSemEntry>>> = Mutex::new(None);
|
|
+
|
|
+fn with_named_sems<R>(f: impl FnOnce(&mut BTreeMap<Vec<u8>, NamedSemEntry>) -> R) -> R {
|
|
+ let mut guard = NAMED_SEMS.lock();
|
|
+ if guard.is_none() {
|
|
+ *guard = Some(BTreeMap::new());
|
|
+ }
|
|
+ f(guard.as_mut().unwrap())
|
|
+}
|
|
+
|
|
+unsafe fn map_named_semaphore(
|
|
+ name: *const c_char,
|
|
+ oflag: c_int,
|
|
+ mode: mode_t,
|
|
+ value: c_uint,
|
|
+) -> *mut sem_t {
|
|
+ let create = (oflag & O_CREAT) != 0;
|
|
+ let shm_flags = if create { O_CREAT | O_EXCL | O_RDWR } else { O_RDWR };
|
|
+ let canonical = alloc::format!("sem.{name_cstr}", name_cstr = unsafe { CStr::from_ptr(name) }.to_str().unwrap_or(""));
|
|
+ let fd = unsafe { shm_open(canonical.as_ptr() as *const c_char, shm_flags, mode) };
|
|
+ if fd < 0 {
|
|
+ return SEM_FAILED_PTR;
|
|
+ }
|
|
+ let sz = core::mem::size_of::<NamedSemaphore>() as usize;
|
|
+ if create {
|
|
+ if Sys::ftruncate(fd, sz as i64).is_err() {
|
|
+ let _ = Sys::close(fd);
|
|
+ return SEM_FAILED_PTR;
|
|
+ }
|
|
+ }
|
|
+ let ptr = unsafe { mmap(core::ptr::null_mut(), sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) };
|
|
+ let _ = Sys::close(fd);
|
|
+ if ptr == MAP_FAILED {
|
|
+ return SEM_FAILED_PTR;
|
|
+ }
|
|
+ let named: &mut NamedSemaphore = unsafe { &mut *ptr.cast::<NamedSemaphore>() };
|
|
+ if create {
|
|
+ unsafe { ptr::write(&mut named.sem, RlctSempahore::new(value)); }
|
|
+ }
|
|
+ &mut named.sem as *mut RlctSempahore as *mut sem_t
|
|
+}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_close.html>.
|
|
// #[unsafe(no_mangle)]
|
|
+#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
|
|
- todo!("named semaphores")
|
|
+ if sem.is_null() || sem == SEM_FAILED_PTR {
|
|
+ ERRNO.set(EINVAL);
|
|
+ return -1;
|
|
+ }
|
|
+ let named_ptr = sem as *mut NamedSemaphore;
|
|
+ let mut should_unmap = false;
|
|
+ with_named_sems(|map| {
|
|
+ let key = map.iter().find(|(_, e)| e.ptr == named_ptr).map(|(k, _)| k.clone());
|
|
+ if let Some(key) = key {
|
|
+ let entry = map.get(&key).unwrap();
|
|
+ let prev = entry.refs.fetch_sub(1, Ordering::Release);
|
|
+ if prev == 1 { should_unmap = true; map.remove(&key); }
|
|
+ } else { should_unmap = true; }
|
|
+ });
|
|
+ if should_unmap {
|
|
+ if unsafe { munmap(named_ptr as *mut crate::platform::types::c_void, core::mem::size_of::<NamedSemaphore>()) } != 0 {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ 0
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_destroy.html>.
|
|
@@ -50,13 +141,31 @@ pub unsafe extern "C" fn sem_init(sem: *mut sem_t, _pshared: c_int, value: c_uin
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_open.html>.
|
|
-// TODO: va_list
|
|
-// #[unsafe(no_mangle)]
|
|
+#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn sem_open(
|
|
name: *const c_char,
|
|
- oflag: c_int, /* (va_list) value: c_uint */
|
|
+ oflag: c_int, /* (va_list) mode: mode_t, value: c_uint */
|
|
) -> *mut sem_t {
|
|
- todo!("named semaphores")
|
|
+ if name.is_null() { ERRNO.set(EINVAL); return SEM_FAILED_PTR; }
|
|
+ let name_bytes = unsafe { CStr::from_ptr(name) }.to_bytes().to_vec();
|
|
+ let create = (oflag & O_CREAT) != 0;
|
|
+ let excl = (oflag & O_EXCL) != 0;
|
|
+ let existing = with_named_sems(|map| map.get(&name_bytes).map(|e| e.ptr));
|
|
+ if let Some(ptr) = existing {
|
|
+ if excl { ERRNO.set(crate::header::errno::EEXIST); return SEM_FAILED_PTR; }
|
|
+ with_named_sems(|map| { if let Some(e) = map.get(&name_bytes) { e.refs.fetch_add(1, Ordering::Relaxed); } });
|
|
+ return ptr as *mut NamedSemaphore as *mut sem_t;
|
|
+ }
|
|
+ let (mode, value): (mode_t, c_uint) = {
|
|
+ let oflag_ptr: *const c_int = &oflag;
|
|
+ let mode_ptr = unsafe { oflag_ptr.add(1) as *const mode_t };
|
|
+ let value_ptr = unsafe { oflag_ptr.add(2) as *const c_uint };
|
|
+ (unsafe { *mode_ptr }, if create { unsafe { *value_ptr } } else { 0 })
|
|
+ };
|
|
+ let ptr = unsafe { map_named_semaphore(name, oflag, mode, value) };
|
|
+ if ptr == SEM_FAILED_PTR { return SEM_FAILED_PTR; }
|
|
+ with_named_sems(|map| { map.insert(name_bytes, NamedSemEntry { ptr: ptr as *mut NamedSemaphore, size: core::mem::size_of::<NamedSemaphore>(), refs: AtomicUsize::new(1), unlinked: false }); });
|
|
+ ptr
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_post.html>.
|
|
@@ -76,9 +185,12 @@ pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_unlink.html>.
|
|
-// #[unsafe(no_mangle)]
|
|
+#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
|
|
- todo!("named semaphores")
|
|
+ if name.is_null() { ERRNO.set(EINVAL); return -1; }
|
|
+ let name_bytes = unsafe { CStr::from_ptr(name) }.to_bytes().to_vec();
|
|
+ with_named_sems(|map| { if let Some(e) = map.get_mut(&name_bytes) { e.unlinked = true; } });
|
|
+ unsafe { shm_unlink(name) }
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_trywait.html>.
|