diff --git a/src/sync/mod.rs b/src/sync/mod.rs index f9e469a..f9a22b4 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -1,6 +1,6 @@ mod mutex; mod condvar; -//mod semaphore; +mod semaphore; pub mod test; pub use self::mutex::*; diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs index 6ee6be7..bbe8ef3 100644 --- a/src/sync/semaphore.rs +++ b/src/sync/semaphore.rs @@ -1,2 +1,73 @@ -use super::mutex; +//! A counting, blocking, semaphore. +//! +//! Borrowed from std at rust 1.7.0 +use super::SpinNoIrqLock as Mutex; +use super::Condvar; + +/// 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 { + // TODO: -> cvar.wait(count) + drop(count); + self.cvar.wait(); + count = self.lock.lock(); + } + *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(); + } +} \ No newline at end of file