diff --git a/src/header/semaphore/mod.rs b/src/header/semaphore/mod.rs index 505d6eba6f934666fdc6eb09955e674125e372cd..5ad4c3c787f7d7438d8d4d1bfb9e361fa8d1f8dd 100644 --- a/src/header/semaphore/mod.rs +++ b/src/header/semaphore/mod.rs @@ -1,61 +1,72 @@ use crate::platform::types::*; +// TODO: Statically verify size and align #[repr(C)] -#[derive(Copy)] +#[derive(Clone, Copy)] pub union sem_t { - pub size: [c_char; 32usize], + pub size: [c_char; 4], pub align: c_long, - _bindgen_union_align: [u64; 4usize], } -impl Clone for sem_t { - fn clone(&self) -> Self { - *self - } -} -// #[no_mangle] -pub extern "C" fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int { - unimplemented!(); +pub type RlctSempahore = crate::sync::Semaphore; + +#[no_mangle] +pub unsafe extern "C" fn sem_init(sem: *mut sem_t, _pshared: c_int, value: c_uint) -> c_int { + sem.cast::<RlctSempahore>().write(RlctSempahore::new(value)); + + 0 } -// #[no_mangle] -pub extern "C" fn sem_destroy(sem: *mut sem_t) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn sem_destroy(sem: *mut sem_t) -> c_int { + core::ptr::drop_in_place(sem.cast::<RlctSempahore>()); + 0 } -/* - *#[no_mangle] - *pub extern "C" fn sem_open(name: *const c_char, - * oflag: c_int, ...) -> *mut sem_t { - * unimplemented!(); - *} - */ +// TODO: va_list // #[no_mangle] -pub extern "C" fn sem_close(sem: *mut sem_t) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn sem_open(name: *const c_char, oflag: c_int, /* (va_list) value: c_uint */) -> *mut sem_t { + todo!("named semaphores") } // #[no_mangle] -pub extern "C" fn sem_unlink(name: *const c_char) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int { + todo!("named semaphores") } // #[no_mangle] -pub extern "C" fn sem_wait(sem: *mut sem_t) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int { + todo!("named semaphores") } -// #[no_mangle] -pub extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int { + get(sem).wait(None); + + 0 } -// #[no_mangle] -pub extern "C" fn sem_post(sem: *mut sem_t) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int { + get(sem).try_wait(); + + 0 } -// #[no_mangle] -pub extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn sem_post(sem: *mut sem_t) -> c_int { + get(sem).post(1); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int { + sval.write(get(sem).value() as c_int); + + 0 +} + +unsafe fn get<'any>(sem: *mut sem_t) -> &'any RlctSempahore { + &*sem.cast() } diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs index aa38929f1eef94d4fbb6818b89f85536a22fbc07..708acafca9ed919622cf58ca4ce211f37d99594d 100644 --- a/src/sync/semaphore.rs +++ b/src/sync/semaphore.rs @@ -7,43 +7,57 @@ use crate::{ platform::{types::*, Pal, Sys}, }; -use core::sync::atomic::Ordering; +use core::sync::atomic::{AtomicU32, Ordering}; pub struct Semaphore { - lock: AtomicLock, + count: AtomicU32, } impl Semaphore { - pub const fn new(value: c_int) -> Self { + pub const fn new(value: c_uint) -> Self { Self { - lock: AtomicLock::new(value), + count: AtomicU32::new(value), } } - pub fn post(&self, count: c_int) { - self.lock.fetch_add(count, Ordering::SeqCst); - self.lock.notify_all(); + // TODO: Acquire-Release ordering? + + pub fn post(&self, count: c_uint) { + self.count.fetch_add(count, Ordering::SeqCst); + // TODO: notify one? + crate::sync::futex_wake(&self.count, i32::MAX); } - pub fn wait(&self, timeout_opt: Option<×pec>) -> Result<(), ()> { + pub fn try_wait(&self) -> u32 { loop { - let value = self.lock.load(Ordering::SeqCst); - if value > 0 { - match self.lock.compare_exchange( - value, - value - 1, - Ordering::SeqCst, - Ordering::SeqCst, - ) { - Ok(_) => { - // Acquired - return Ok(()); - } - Err(_) => (), + let value = self.count.load(Ordering::SeqCst); + + if value == 0 { return 0 } + + match self.count.compare_exchange_weak( + value, + value - 1, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => { + // Acquired + return value; } - // Try again (as long as value > 0) - continue; + Err(_) => (), } + // Try again (as long as value > 0) + } + } + + pub fn wait(&self, timeout_opt: Option<×pec>) -> Result<(), ()> { + loop { + let value = self.try_wait(); + + if value == 0 { + return Ok(()); + } + if let Some(timeout) = timeout_opt { let mut time = timespec::default(); clock_gettime(CLOCK_MONOTONIC, &mut time); @@ -64,12 +78,16 @@ impl Semaphore { } relative.tv_sec -= time.tv_sec; relative.tv_nsec -= time.tv_nsec; - self.lock.wait_if(value, Some(&relative)); + + crate::sync::futex_wait(&self.count, value, Some(&relative)); } } else { // Use futex to wait for the next change, without a timeout - self.lock.wait_if(value, None); + crate::sync::futex_wait(&self.count, value, None); } } } + pub fn value(&self) -> c_uint { + self.count.load(Ordering::SeqCst) + } }