moirai_async/sync/
semaphore.rs1#![expect(
10 clippy::unwrap_used,
11 reason = "ratchet MOIRAI-UNWRAP-1: pre-existing debt"
12)]
13
14use std::future::Future;
15use std::pin::Pin;
16use std::sync::Mutex;
17use std::task::{Context, Poll};
18
19use crate::sync::wait_queue::{WaitQueue, WaiterPoll};
20
21pub struct Semaphore {
23 state: Mutex<SemaphoreState>,
24}
25
26struct SemaphoreState {
27 available: usize,
28 waiters: WaitQueue<()>,
31}
32
33impl Semaphore {
34 pub fn new(permits: usize) -> Self {
36 Self {
37 state: Mutex::new(SemaphoreState {
38 available: permits,
39 waiters: WaitQueue::new(),
40 }),
41 }
42 }
43
44 pub fn acquire(&self) -> SemaphoreAcquire<'_> {
46 SemaphoreAcquire {
47 semaphore: self,
48 id: None,
49 }
50 }
51
52 pub fn try_acquire(&self) -> Option<SemaphorePermit<'_>> {
54 let mut state = self.state.lock().unwrap();
55 if state.available > 0 {
56 state.available -= 1;
57 Some(SemaphorePermit { semaphore: self })
58 } else {
59 None
60 }
61 }
62
63 pub fn available_permits(&self) -> usize {
65 self.state.lock().unwrap().available
66 }
67
68 fn release(&self) {
69 let waker = {
74 let mut state = self.state.lock().unwrap();
75 let waker = state.waiters.grant_oldest(());
76 if waker.is_none() {
77 state.available += 1;
78 }
79 waker
80 };
81 if let Some(waker) = waker {
82 waker.wake();
83 }
84 }
85}
86
87pub struct SemaphoreAcquire<'a> {
89 semaphore: &'a Semaphore,
90 id: Option<u64>,
91}
92
93impl<'a> Future for SemaphoreAcquire<'a> {
94 type Output = SemaphorePermit<'a>;
95
96 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
97 let mut state = self.semaphore.state.lock().unwrap();
98
99 if let Some(id) = self.id {
101 match state.waiters.poll_waiter(id, cx.waker()) {
102 WaiterPoll::Granted(()) => {
103 self.id = None;
104 return Poll::Ready(SemaphorePermit {
105 semaphore: self.semaphore,
106 });
107 }
108 WaiterPoll::Pending => return Poll::Pending,
109 WaiterPoll::NotRegistered => {}
111 }
112 }
113
114 if state.available > 0 {
116 state.available -= 1;
117 if let Some(id) = self.id.take() {
118 let _removed_grant = state.waiters.deregister(id);
119 }
120 return Poll::Ready(SemaphorePermit {
121 semaphore: self.semaphore,
122 });
123 }
124
125 if self.id.is_none() {
127 self.id = Some(state.waiters.register(cx.waker().clone()));
128 }
129
130 Poll::Pending
131 }
132}
133
134impl<'a> Drop for SemaphoreAcquire<'a> {
135 fn drop(&mut self) {
136 if let Some(id) = self.id
137 && let Ok(mut state) = self.semaphore.state.lock()
138 {
139 if state.waiters.deregister(id).is_some() {
142 drop(state);
143 self.semaphore.release();
144 }
145 }
146 }
147}
148
149pub struct SemaphorePermit<'a> {
151 semaphore: &'a Semaphore,
152}
153
154impl<'a> Drop for SemaphorePermit<'a> {
155 fn drop(&mut self) {
156 self.semaphore.release();
157 }
158}
159
160#[cfg(test)]
161mod tests;