//! A counting, blocking, semaphore. //! //! Same as [std::sync::Semaphore at rust 1.7.0](https://docs.rs/std-semaphore/0.1.0/std_semaphore/) use super::Condvar; use super::SpinNoIrqLock as Mutex; /// A counting, blocking, semaphore. pub struct Semaphore { lock: Mutex, cvar: Condvar, } /// An RAII guard which will release a resource acquired from a semaphore when /// dropped. pub struct SemaphoreGuard<'a> { sem: &'a Semaphore, } impl Semaphore { /// Creates a new semaphore with the initial count specified. /// /// The count specified can be thought of as a number of resources, and a /// call to `acquire` or `access` will block until at least one resource is /// available. It is valid to initialize a semaphore with a negative count. pub fn new(count: isize) -> Semaphore { Semaphore { lock: Mutex::new(count), cvar: Condvar::new(), } } /// Acquires a resource of this semaphore, blocking the current thread until /// it can do so. /// /// This method will block until the internal count of the semaphore is at /// least 1. pub fn acquire(&self) { let mut count = self.lock.lock(); while *count <= 0 { count = self.cvar.wait(count); } *count -= 1; } /// Release a resource from this semaphore. /// /// This will increment the number of resources in this semaphore by 1 and /// will notify any pending waiters in `acquire` or `access` if necessary. pub fn release(&self) { *self.lock.lock() += 1; self.cvar.notify_one(); } /// Acquires a resource of this semaphore, returning an RAII guard to /// release the semaphore when dropped. /// /// This function is semantically equivalent to an `acquire` followed by a /// `release` when the guard returned is dropped. pub fn access(&self) -> SemaphoreGuard { self.acquire(); SemaphoreGuard { sem: self } } } impl<'a> Drop for SemaphoreGuard<'a> { fn drop(&mut self) { self.sem.release(); } }