dtact_util/sync/
semaphore.rs1use super::wait_queue::WaitQueue;
5use std::sync::atomic::{AtomicUsize, Ordering};
6use std::task::{Context, Poll};
7
8#[repr(align(64))]
12pub struct Semaphore {
13 permits: AtomicUsize,
14 wait: WaitQueue,
15}
16
17impl Semaphore {
18 #[must_use]
20 pub const fn new(permits: usize) -> Self {
21 Self {
22 permits: AtomicUsize::new(permits),
23 wait: WaitQueue::new(),
24 }
25 }
26
27 #[must_use]
29 #[inline(always)]
30 pub fn available_permits(&self) -> usize {
31 self.permits.load(Ordering::Relaxed)
32 }
33
34 #[inline(always)]
36 pub fn add_permits(&self, n: usize) {
37 self.permits.fetch_add(n, Ordering::Release);
38 self.wait.wake_all();
39 }
40
41 #[inline(always)]
43 pub async fn acquire(&self) -> SemaphorePermit<'_> {
44 std::future::poll_fn(|cx| self.poll_acquire(cx)).await
45 }
46
47 #[inline(always)]
52 pub fn try_acquire(&self) -> Result<SemaphorePermit<'_>, TryAcquireError> {
53 self.try_acquire_one()
58 .then(|| SemaphorePermit { sem: self })
59 .ok_or(TryAcquireError::NoPermits)
60 }
61
62 #[inline]
63 fn try_acquire_one(&self) -> bool {
64 let mut current = self.permits.load(Ordering::Relaxed);
65 loop {
66 if current == 0 {
67 return false;
68 }
69 match self.permits.compare_exchange_weak(
70 current,
71 current - 1,
72 Ordering::Acquire,
73 Ordering::Relaxed,
74 ) {
75 Ok(_) => return true,
76 Err(observed) => current = observed,
77 }
78 }
79 }
80
81 #[inline]
82 fn poll_acquire(&self, cx: &Context<'_>) -> Poll<SemaphorePermit<'_>> {
83 if !self.wait.has_waiters() && self.try_acquire_one() {
90 return Poll::Ready(SemaphorePermit { sem: self });
91 }
92 let token = self.wait.register(cx.waker());
95 if self.try_acquire_one() {
96 self.wait.cancel(token);
97 return Poll::Ready(SemaphorePermit { sem: self });
98 }
99 Poll::Pending
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105#[repr(align(64))]
106pub enum TryAcquireError {
107 NoPermits,
109}
110
111impl std::fmt::Display for TryAcquireError {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 f.write_str("no permits available")
114 }
115}
116
117impl std::error::Error for TryAcquireError {}
118
119#[repr(align(64))]
122pub struct SemaphorePermit<'a> {
123 sem: &'a Semaphore,
124}
125
126impl Drop for SemaphorePermit<'_> {
127 #[inline(always)]
128 fn drop(&mut self) {
129 self.sem.permits.fetch_add(1, Ordering::Release);
130 self.sem.wait.wake_one();
131 }
132}