1 use super::semaphore_ll as ll; // low level implementation 2 use crate::future::poll_fn; 3 4 /// Counting semaphore performing asynchronous permit aquisition. 5 /// 6 /// A semaphore maintains a set of permits. Permits are used to synchronize 7 /// access to a shared resource. A semaphore differs from a mutex in that it 8 /// can allow more than one concurrent caller to access the shared resource at a 9 /// time. 10 /// 11 /// When `acquire` is called and the semaphore has remaining permits, the 12 /// function immediately returns a permit. However, if no remaining permits are 13 /// available, `acquire` (asynchronously) waits until an outstanding permit is 14 /// dropped. At this point, the freed permit is assigned to the caller. 15 #[derive(Debug)] 16 pub struct Semaphore { 17 /// The low level semaphore 18 ll_sem: ll::Semaphore, 19 } 20 21 /// A permit from the semaphore 22 #[must_use] 23 #[derive(Debug)] 24 pub struct SemaphorePermit<'a> { 25 sem: &'a Semaphore, 26 // the low level permit 27 ll_permit: ll::Permit, 28 } 29 30 /// Error returned from the [`Semaphore::try_acquire`] function. 31 /// 32 /// A `try_acquire` operation can only fail if the semaphore has no available 33 /// permits. 34 /// 35 /// [`Semaphore::try_acquire`]: Semaphore::try_acquire 36 #[derive(Debug)] 37 pub struct TryAcquireError(()); 38 39 impl Semaphore { 40 /// Creates a new semaphore with the initial number of permits new(permits: usize) -> Self41 pub fn new(permits: usize) -> Self { 42 Self { 43 ll_sem: ll::Semaphore::new(permits), 44 } 45 } 46 47 /// Returns the current number of available permits available_permits(&self) -> usize48 pub fn available_permits(&self) -> usize { 49 self.ll_sem.available_permits() 50 } 51 52 /// Adds `n` new permits to the semaphore. add_permits(&self, n: usize)53 pub fn add_permits(&self, n: usize) { 54 self.ll_sem.add_permits(n); 55 } 56 57 /// Acquires permit from the semaphore acquire(&self) -> SemaphorePermit<'_>58 pub async fn acquire(&self) -> SemaphorePermit<'_> { 59 let mut permit = SemaphorePermit { 60 sem: &self, 61 ll_permit: ll::Permit::new(), 62 }; 63 poll_fn(|cx| permit.ll_permit.poll_acquire(cx, 1, &self.ll_sem)) 64 .await 65 .unwrap(); 66 permit 67 } 68 69 /// Tries to acquire a permit form the semaphore try_acquire(&self) -> Result<SemaphorePermit<'_>, TryAcquireError>70 pub fn try_acquire(&self) -> Result<SemaphorePermit<'_>, TryAcquireError> { 71 let mut ll_permit = ll::Permit::new(); 72 match ll_permit.try_acquire(1, &self.ll_sem) { 73 Ok(_) => Ok(SemaphorePermit { 74 sem: self, 75 ll_permit, 76 }), 77 Err(_) => Err(TryAcquireError(())), 78 } 79 } 80 } 81 82 impl<'a> SemaphorePermit<'a> { 83 /// Forgets the permit **without** releasing it back to the semaphore. 84 /// This can be used to reduce the amount of permits available from a 85 /// semaphore. forget(mut self)86 pub fn forget(mut self) { 87 self.ll_permit.forget(1); 88 } 89 } 90 91 impl<'a> Drop for SemaphorePermit<'_> { drop(&mut self)92 fn drop(&mut self) { 93 self.ll_permit.release(1, &self.sem.ll_sem); 94 } 95 } 96