use core::cell::UnsafeCell;
use crate::{Condition, Mutex};
pub struct Semaphore {
mutex: Mutex,
cond: Condition,
permits: UnsafeCell<usize>,
}
unsafe impl Sync for Semaphore {}
unsafe impl Send for Semaphore {}
impl Default for Semaphore {
fn default() -> Self {
Self::new()
}
}
impl Semaphore {
pub const fn new() -> Self {
Self::with_permits(0)
}
pub const fn with_permits(permits: usize) -> Self {
Self {
mutex: Mutex::new(),
cond: Condition::new(),
permits: UnsafeCell::new(permits),
}
}
pub fn wait(&self) {
self.mutex.lock();
scopeguard::defer! { self.mutex.unlock(); }
while unsafe { *self.permits.get() } == 0 {
self.cond.wait(&self.mutex);
}
unsafe { *self.permits.get() -= 1 };
if unsafe { *self.permits.get() } > 0 {
self.cond.signal();
}
}
pub fn post(&self) {
self.mutex.lock();
scopeguard::defer! { self.mutex.unlock(); }
unsafe { *self.permits.get() += 1 };
self.cond.signal();
}
}