--- a/src/header/semaphore/mod.rs 2026-04-25 17:07:53.742796721 +0100 +++ b/src/header/semaphore/mod.rs 2026-04-25 17:08:54.527084219 +0100 @@ -2,12 +2,24 @@ //! //! See . +use core::mem::size_of; + use crate::{ + c_str::CStr, header::{ bits_timespec::timespec, + errno::{EEXIST, EINVAL}, + fcntl::{O_CREAT, O_EXCL, O_RDWR}, + sys_mman::{ + mmap, munmap, shm_open, shm_unlink, MAP_SHARED, MAP_FAILED, PROT_READ, PROT_WRITE, + }, time::{CLOCK_MONOTONIC, CLOCK_REALTIME}, + unistd::{close, ftruncate}, + }, + platform::{ + ERRNO, + types::{c_char, c_int, c_long, c_uint, clockid_t, c_void, mode_t, off_t, size_t}, }, - platform::types::{c_char, c_int, c_long, c_uint, clockid_t}, }; /// See . @@ -18,12 +30,17 @@ pub size: [c_char; 4], pub align: c_long, } + +/// Pointer value returned by `sem_open` on failure. +/// cbindgen:ignore +pub const SEM_FAILED: *mut sem_t = usize::MAX as *mut sem_t; + pub type RlctSempahore = crate::sync::Semaphore; /// See . -// #[unsafe(no_mangle)] +#[unsafe(no_mangle)] pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int { - todo!("named semaphores") + unsafe { munmap(sem.cast::(), size_of::()) } } /// See . @@ -50,13 +67,105 @@ } /// See . -// 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, + mut __valist: ... ) -> *mut sem_t { - todo!("named semaphores") + // Validate name: must start with '/', no embedded '/'. + if name.is_null() { + ERRNO.set(EINVAL); + return SEM_FAILED; + } + + let name_c = unsafe { CStr::from_ptr(name) }; + let name_bytes = name_c.to_bytes(); + if name_bytes.is_empty() || name_bytes[0] != b'/' { + ERRNO.set(EINVAL); + return SEM_FAILED; + } + if name_bytes[1..].iter().any(|&b| b == b'/') { + ERRNO.set(EINVAL); + return SEM_FAILED; + } + + let creat = oflag & O_CREAT == O_CREAT; + let excl = oflag & O_EXCL == O_EXCL; + + let (mode, value): (mode_t, c_uint) = if creat { + ( + unsafe { __valist.arg::() }, + unsafe { __valist.arg::() }, + ) + } else { + (0, 0) + }; + + // Open or create the shared memory backing. + let (fd, created) = if creat && excl { + // O_CREAT | O_EXCL: must create exclusively. + let fd = unsafe { shm_open(name, O_CREAT | O_EXCL | O_RDWR, mode) }; + if fd < 0 { + return SEM_FAILED; + } + (fd, true) + } else if creat { + // O_CREAT without O_EXCL: try exclusive first, fall back to open. + let fd = unsafe { shm_open(name, O_CREAT | O_EXCL | O_RDWR, mode) }; + if fd >= 0 { + (fd, true) + } else if ERRNO.get() == EEXIST { + let fd = unsafe { shm_open(name, O_RDWR, 0) }; + if fd < 0 { + return SEM_FAILED; + } + (fd, false) + } else { + return SEM_FAILED; + } + } else { + // No O_CREAT: open existing. + let fd = unsafe { shm_open(name, O_RDWR, 0) }; + if fd < 0 { + return SEM_FAILED; + } + (fd, false) + }; + + // Set size if we created the backing. + if created { + if unsafe { ftruncate(fd, size_of::() as off_t) } < 0 { + let _ = unsafe { close(fd) }; + return SEM_FAILED; + } + } + + // Map the shared memory. + let ptr = unsafe { + mmap( + core::ptr::null_mut(), + size_of::(), + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0, + ) + }; + let _ = unsafe { close(fd) }; + + if ptr == MAP_FAILED { + return SEM_FAILED; + } + + let sem_ptr = ptr.cast::(); + + // Initialize the semaphore value if we created the backing. + if created { + unsafe { sem_ptr.cast::().write(RlctSempahore::new(value)) }; + } + + sem_ptr } /// See . @@ -76,10 +185,10 @@ } /// See . -// #[unsafe(no_mangle)] +#[unsafe(no_mangle)] pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int { - todo!("named semaphores") + unsafe { shm_unlink(name) } } /// See . --- a/src/header/semaphore/cbindgen.toml 2026-04-25 17:07:53.743979154 +0100 +++ b/src/header/semaphore/cbindgen.toml 2026-04-25 17:09:18.310792692 +0100 @@ -3,6 +3,9 @@ after_includes = """ #include // for timespec """ +trailer = """ +#define SEM_FAILED ((sem_t *) -1) +""" language = "C" style = "Type" no_includes = true