use super::pthread;
use core::mem::MaybeUninit;
use hierr::{Error, Result};
pub struct Semaphore {
sem: MaybeUninit<pthread::sem_t>,
}
unsafe impl Send for Semaphore {}
unsafe impl Sync for Semaphore {}
impl Drop for Semaphore {
fn drop(&mut self) {
unsafe { pthread::sem_destroy(self.sem.as_mut_ptr()) };
}
}
impl Semaphore {
pub fn new(init_value: u32) -> Result<Self> {
let this = Self {
sem: MaybeUninit::uninit(),
};
let ret = unsafe { pthread::sem_init(this.get_sem(), 0, init_value as pthread::c_uint) };
if ret == 0 {
Ok(this)
} else {
Err(Error::last())
}
}
pub fn post(&self) {
unsafe { pthread::sem_post(self.get_sem()) };
}
pub fn wait(&self) {
unsafe { pthread::sem_wait(self.get_sem()) };
}
fn get_sem(&self) -> *mut pthread::sem_t {
self.sem.as_ptr().cast_mut()
}
}
#[cfg(test)]
mod test {
use crate::*;
use core::sync::atomic::Ordering::*;
use core::sync::atomic::*;
use hipool::*;
#[test]
fn test_semaphore() {
let sem = Arc::new(Semaphore::new(0).unwrap()).unwrap();
let cloned = sem.clone();
static GVALUE: AtomicI32 = AtomicI32::new(0);
let _ = spawn_with(
move || {
let _ = GVALUE.fetch_add(1, Relaxed);
cloned.post();
},
&ThrdAttr::new().set_detachstate(true),
)
.unwrap();
sem.wait();
assert_eq!(GVALUE.load(Relaxed), 1);
}
}