async_lock/semaphore.rs
1use core::fmt;
2use core::marker::PhantomPinned;
3use core::mem;
4use core::pin::Pin;
5use core::task::{ready, Poll};
6
7use crate::sync::atomic::{AtomicUsize, Ordering};
8
9use alloc::sync::Arc;
10
11use event_listener::{Event, EventListener};
12use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy};
13
14/// A counter for limiting the number of concurrent operations.
15#[derive(Debug)]
16pub struct Semaphore {
17 count: AtomicUsize,
18 event: Event,
19}
20
21impl Semaphore {
22 const_fn! {
23 const_if: #[cfg(not(loom))];
24 /// Creates a new semaphore with a limit of `n` concurrent operations.
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// use async_lock::Semaphore;
30 ///
31 /// let s = Semaphore::new(5);
32 /// ```
33 pub const fn new(n: usize) -> Semaphore {
34 Semaphore {
35 count: AtomicUsize::new(n),
36 event: Event::new(),
37 }
38 }
39 }
40
41 /// Attempts to get a permit for a concurrent operation.
42 ///
43 /// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, a
44 /// guard is returned that releases the mutex when dropped.
45 ///
46 /// # Examples
47 ///
48 /// ```
49 /// use async_lock::Semaphore;
50 ///
51 /// let s = Semaphore::new(2);
52 ///
53 /// let g1 = s.try_acquire().unwrap();
54 /// let g2 = s.try_acquire().unwrap();
55 ///
56 /// assert!(s.try_acquire().is_none());
57 /// drop(g2);
58 /// assert!(s.try_acquire().is_some());
59 /// ```
60 pub fn try_acquire(&self) -> Option<SemaphoreGuard<'_>> {
61 let mut count = self.count.load(Ordering::Acquire);
62 loop {
63 if count == 0 {
64 return None;
65 }
66
67 match self.count.compare_exchange_weak(
68 count,
69 count - 1,
70 Ordering::AcqRel,
71 Ordering::Acquire,
72 ) {
73 Ok(_) => return Some(SemaphoreGuard(self)),
74 Err(c) => count = c,
75 }
76 }
77 }
78
79 /// Waits for a permit for a concurrent operation.
80 ///
81 /// Returns a guard that releases the permit when dropped.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// # futures_lite::future::block_on(async {
87 /// use async_lock::Semaphore;
88 ///
89 /// let s = Semaphore::new(2);
90 /// let guard = s.acquire().await;
91 /// # });
92 /// ```
93 pub fn acquire(&self) -> Acquire<'_> {
94 Acquire::_new(AcquireInner {
95 semaphore: self,
96 listener: None,
97 _pin: PhantomPinned,
98 })
99 }
100
101 /// Waits for a permit for a concurrent operation.
102 ///
103 /// Returns a guard that releases the permit when dropped.
104 ///
105 /// # Blocking
106 ///
107 /// Rather than using asynchronous waiting, like the [`acquire`][Semaphore::acquire] method,
108 /// this method will block the current thread until the permit is acquired.
109 ///
110 /// This method should not be used in an asynchronous context. It is intended to be
111 /// used in a way that a semaphore can be used in both asynchronous and synchronous contexts.
112 /// Calling this method in an asynchronous context may result in a deadlock.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use async_lock::Semaphore;
118 ///
119 /// let s = Semaphore::new(2);
120 /// let guard = s.acquire_blocking();
121 /// ```
122 #[cfg(all(feature = "std", not(target_family = "wasm")))]
123 #[inline]
124 pub fn acquire_blocking(&self) -> SemaphoreGuard<'_> {
125 self.acquire().wait()
126 }
127
128 /// Attempts to get an owned permit for a concurrent operation.
129 ///
130 /// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, an
131 /// owned guard is returned that releases the mutex when dropped.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use async_lock::Semaphore;
137 /// use std::sync::Arc;
138 ///
139 /// let s = Arc::new(Semaphore::new(2));
140 ///
141 /// let g1 = s.try_acquire_arc().unwrap();
142 /// let g2 = s.try_acquire_arc().unwrap();
143 ///
144 /// assert!(s.try_acquire_arc().is_none());
145 /// drop(g2);
146 /// assert!(s.try_acquire_arc().is_some());
147 /// ```
148 pub fn try_acquire_arc(self: &Arc<Self>) -> Option<SemaphoreGuardArc> {
149 let mut count = self.count.load(Ordering::Acquire);
150 loop {
151 if count == 0 {
152 return None;
153 }
154
155 match self.count.compare_exchange_weak(
156 count,
157 count - 1,
158 Ordering::AcqRel,
159 Ordering::Acquire,
160 ) {
161 Ok(_) => return Some(SemaphoreGuardArc(Some(self.clone()))),
162 Err(c) => count = c,
163 }
164 }
165 }
166
167 /// Waits for an owned permit for a concurrent operation.
168 ///
169 /// Returns a guard that releases the permit when dropped.
170 ///
171 /// # Examples
172 ///
173 /// ```
174 /// # futures_lite::future::block_on(async {
175 /// use async_lock::Semaphore;
176 /// use std::sync::Arc;
177 ///
178 /// let s = Arc::new(Semaphore::new(2));
179 /// let guard = s.acquire_arc().await;
180 /// # });
181 /// ```
182 pub fn acquire_arc(self: &Arc<Self>) -> AcquireArc {
183 AcquireArc::_new(AcquireArcInner {
184 semaphore: self.clone(),
185 listener: None,
186 _pin: PhantomPinned,
187 })
188 }
189
190 /// Waits for an owned permit for a concurrent operation.
191 ///
192 /// Returns a guard that releases the permit when dropped.
193 ///
194 /// # Blocking
195 ///
196 /// Rather than using asynchronous waiting, like the [`acquire_arc`][Semaphore::acquire_arc] method,
197 /// this method will block the current thread until the permit is acquired.
198 ///
199 /// This method should not be used in an asynchronous context. It is intended to be
200 /// used in a way that a semaphore can be used in both asynchronous and synchronous contexts.
201 /// Calling this method in an asynchronous context may result in a deadlock.
202 ///
203 /// # Examples
204 ///
205 /// ```
206 /// use std::sync::Arc;
207 /// use async_lock::Semaphore;
208 ///
209 /// let s = Arc::new(Semaphore::new(2));
210 /// let guard = s.acquire_arc_blocking();
211 /// ```
212 #[cfg(all(feature = "std", not(target_family = "wasm")))]
213 #[inline]
214 pub fn acquire_arc_blocking(self: &Arc<Self>) -> SemaphoreGuardArc {
215 self.acquire_arc().wait()
216 }
217
218 /// Adds `n` additional permits to the semaphore.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// use async_lock::Semaphore;
224 ///
225 /// # futures_lite::future::block_on(async {
226 /// let s = Semaphore::new(1);
227 ///
228 /// let _guard = s.acquire().await;
229 /// assert!(s.try_acquire().is_none());
230 ///
231 /// s.add_permits(2);
232 ///
233 /// let _guard = s.acquire().await;
234 /// let _guard = s.acquire().await;
235 /// # });
236 /// ```
237 pub fn add_permits(&self, n: usize) {
238 self.count.fetch_add(n, Ordering::AcqRel);
239 self.event.notify(n);
240 }
241
242 /// Returns the current number of available permits.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use async_lock::Semaphore;
248 ///
249 /// let s = Semaphore::new(2);
250 /// assert_eq!(s.available_permits(), 2);
251 ///
252 /// let gaurd = s.try_acquire().unwrap();
253 /// assert_eq!(s.available_permits(), 1);
254 ///
255 /// drop(gaurd);
256 /// ```
257 pub fn available_permits(&self) -> usize {
258 self.count.load(Ordering::Acquire)
259 }
260}
261
262easy_wrapper! {
263 /// The future returned by [`Semaphore::acquire`].
264 pub struct Acquire<'a>(AcquireInner<'a> => SemaphoreGuard<'a>);
265 #[cfg(all(feature = "std", not(target_family = "wasm")))]
266 pub(crate) wait();
267}
268
269pin_project_lite::pin_project! {
270 struct AcquireInner<'a> {
271 // The semaphore being acquired.
272 semaphore: &'a Semaphore,
273
274 // The listener waiting on the semaphore.
275 listener: Option<EventListener>,
276
277 // Keeping this future `!Unpin` enables future optimizations.
278 #[pin]
279 _pin: PhantomPinned
280 }
281}
282
283impl fmt::Debug for Acquire<'_> {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 f.write_str("Acquire { .. }")
286 }
287}
288
289impl<'a> EventListenerFuture for AcquireInner<'a> {
290 type Output = SemaphoreGuard<'a>;
291
292 fn poll_with_strategy<'x, S: Strategy<'x>>(
293 self: Pin<&mut Self>,
294 strategy: &mut S,
295 cx: &mut S::Context,
296 ) -> Poll<Self::Output> {
297 let this = self.project();
298
299 loop {
300 match this.semaphore.try_acquire() {
301 Some(guard) => return Poll::Ready(guard),
302 None => {
303 // Wait on the listener.
304 if this.listener.is_none() {
305 *this.listener = Some(this.semaphore.event.listen());
306 } else {
307 ready!(strategy.poll(this.listener, cx));
308 }
309 }
310 }
311 }
312 }
313}
314
315easy_wrapper! {
316 /// The future returned by [`Semaphore::acquire_arc`].
317 pub struct AcquireArc(AcquireArcInner => SemaphoreGuardArc);
318 #[cfg(all(feature = "std", not(target_family = "wasm")))]
319 pub(crate) wait();
320}
321
322pin_project_lite::pin_project! {
323 struct AcquireArcInner {
324 // The semaphore being acquired.
325 semaphore: Arc<Semaphore>,
326
327 // The listener waiting on the semaphore.
328 listener: Option<EventListener>,
329
330 // Keeping this future `!Unpin` enables future optimizations.
331 #[pin]
332 _pin: PhantomPinned
333 }
334}
335
336impl fmt::Debug for AcquireArc {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 f.write_str("AcquireArc { .. }")
339 }
340}
341
342impl EventListenerFuture for AcquireArcInner {
343 type Output = SemaphoreGuardArc;
344
345 fn poll_with_strategy<'x, S: Strategy<'x>>(
346 self: Pin<&mut Self>,
347 strategy: &mut S,
348 cx: &mut S::Context,
349 ) -> Poll<Self::Output> {
350 let this = self.project();
351
352 loop {
353 match this.semaphore.try_acquire_arc() {
354 Some(guard) => return Poll::Ready(guard),
355 None => {
356 // Wait on the listener.
357 if this.listener.is_none() {
358 *this.listener = Some(this.semaphore.event.listen());
359 } else {
360 ready!(strategy.poll(this.listener, cx));
361 }
362 }
363 }
364 }
365 }
366}
367
368/// A guard that releases the acquired permit.
369#[clippy::has_significant_drop]
370#[derive(Debug)]
371pub struct SemaphoreGuard<'a>(&'a Semaphore);
372
373impl SemaphoreGuard<'_> {
374 /// Drops the guard _without_ releasing the acquired permit.
375 #[inline]
376 pub fn forget(self) {
377 mem::forget(self);
378 }
379}
380
381impl Drop for SemaphoreGuard<'_> {
382 fn drop(&mut self) {
383 self.0.count.fetch_add(1, Ordering::AcqRel);
384 self.0.event.notify(1);
385 }
386}
387
388/// An owned guard that releases the acquired permit.
389#[clippy::has_significant_drop]
390#[derive(Debug)]
391pub struct SemaphoreGuardArc(Option<Arc<Semaphore>>);
392
393impl SemaphoreGuardArc {
394 /// Drops the guard _without_ releasing the acquired permit.
395 /// (Will still decrement the `Arc` reference count.)
396 #[inline]
397 pub fn forget(mut self) {
398 // Drop the inner `Arc` in order to decrement the reference count.
399 // FIXME: get rid of the `Option` once RFC 3466 or equivalent becomes available.
400 drop(self.0.take());
401 mem::forget(self);
402 }
403}
404
405impl Drop for SemaphoreGuardArc {
406 fn drop(&mut self) {
407 let opt = self.0.take().unwrap();
408 opt.count.fetch_add(1, Ordering::AcqRel);
409 opt.event.notify(1);
410 }
411}