diff --git a/src/header/semaphore/cbindgen.toml b/src/header/semaphore/cbindgen.toml index be8f845..a96854c 100644 --- a/src/header/semaphore/cbindgen.toml +++ b/src/header/semaphore/cbindgen.toml @@ -3,6 +3,9 @@ include_guard = "_RELIBC_SEMAPHORE_H" after_includes = """ #include // for timespec """ +trailer = """ +#define SEM_FAILED ((sem_t *) -1) +""" language = "C" style = "Type" no_includes = true diff --git a/src/header/semaphore/mod.rs b/src/header/semaphore/mod.rs index 0ca2fa9..2dd1bc2 100644 --- a/src/header/semaphore/mod.rs +++ b/src/header/semaphore/mod.rs @@ -2,111 +2,183 @@ //! //! See . +use core::mem::size_of; + use crate::{ + c_str::CStr, header::{ bits_timespec::timespec, + errno::{EEXIST, EAGAIN, EINVAL, ETIMEDOUT}, + fcntl::{O_CREAT, O_EXCL, O_RDWR}, + sys_mman::{ + mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, 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}, }, - platform::types::{c_char, c_int, c_long, c_uint, clockid_t}, }; -/// See . -// TODO: Statically verify size and align #[repr(C)] #[derive(Clone, Copy)] pub union sem_t { pub size: [c_char; 4], pub align: c_long, } + +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 . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_destroy(sem: *mut sem_t) -> c_int { unsafe { core::ptr::drop_in_place(sem.cast::()) }; 0 } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int { unsafe { sval.write(get(sem).value() as c_int) }; - 0 } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_init(sem: *mut sem_t, _pshared: c_int, value: c_uint) -> c_int { unsafe { sem.cast::().write(RlctSempahore::new(value)) }; - 0 } -/// 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") + 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) + }; + let (fd, created) = if creat && excl { + let fd = unsafe { shm_open(name, O_CREAT | O_EXCL | O_RDWR, mode) }; + if fd < 0 { return SEM_FAILED; } + (fd, true) + } else if creat { + 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 { + let fd = unsafe { shm_open(name, O_RDWR, 0) }; + if fd < 0 { return SEM_FAILED; } + (fd, false) + }; + if created { + if ftruncate(fd, size_of::() as off_t) < 0 { + let _ = close(fd); + return SEM_FAILED; + } + } + let ptr = unsafe { + mmap( + core::ptr::null_mut(), + size_of::(), + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0, + ) + }; + let _ = close(fd); + if ptr == MAP_FAILED { return SEM_FAILED; } + let sem_ptr = ptr.cast::(); + if created { + unsafe { sem_ptr.cast::().write(RlctSempahore::new(value)) }; + } + sem_ptr } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_post(sem: *mut sem_t) -> c_int { unsafe { get(sem) }.post(1); - 0 } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int { - unsafe { get(sem) }.try_wait(); - + if unsafe { get(sem) }.try_wait() == 0 { + ERRNO.set(EAGAIN); + return -1; + } 0 } -/// 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 . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int { - if let Ok(()) = unsafe { get(sem) }.wait(None, CLOCK_MONOTONIC) {}; // TODO handle error - + if let Err(()) = unsafe { get(sem) }.wait(None, CLOCK_MONOTONIC) { + ERRNO.set(EINVAL); + return -1; + } 0 } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_clockwait( sem: *mut sem_t, clock_id: clockid_t, abstime: *const timespec, ) -> c_int { - if let Ok(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), clock_id) {}; // TODO handle error - + if let Err(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), clock_id) { + ERRNO.set(ETIMEDOUT); + return -1; + } 0 } -/// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn sem_timedwait(sem: *mut sem_t, abstime: *const timespec) -> c_int { - if let Ok(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), CLOCK_REALTIME) { - }; // TODO handle error - + if let Err(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), CLOCK_REALTIME) { + ERRNO.set(ETIMEDOUT); + return -1; + } 0 } diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs index ce14961..0c280d9 100644 --- a/src/sync/semaphore.rs +++ b/src/sync/semaphore.rs @@ -58,7 +58,7 @@ impl Semaphore { loop { let value = self.try_wait(); - if value == 0 { + if value > 0 { return Ok(()); }