nuclei/sync/local/
semaphore.rs1use core::cell::Cell;
12use core::fmt;
13use core::future::Future;
14use core::pin::Pin;
15use core::task::{Context, Poll};
16
17use super::waiters::{Key, State, Waiters};
18use crate::sync::{AcquireError, TryAcquireError};
19
20pub struct Semaphore {
42 permits: Cell<usize>,
43 closed: Cell<bool>,
44 waiters: Waiters,
45}
46
47impl Semaphore {
48 pub const MAX_PERMITS: usize = usize::MAX >> 3;
50
51 pub const fn new(permits: usize) -> Self {
57 assert!(
58 permits <= Self::MAX_PERMITS,
59 "a semaphore cannot hold more than Semaphore::MAX_PERMITS"
60 );
61 Self {
62 permits: Cell::new(permits),
63 closed: Cell::new(false),
64 waiters: Waiters::new(),
65 }
66 }
67
68 pub fn available_permits(&self) -> usize {
71 self.permits.get()
72 }
73
74 #[track_caller]
82 pub fn add_permits(&self, n: usize) {
83 let total = self.permits.get().saturating_add(n);
84 assert!(
85 total <= Self::MAX_PERMITS,
86 "a semaphore cannot hold more than Semaphore::MAX_PERMITS"
87 );
88 self.permits.set(total);
89 self.serve();
90 }
91
92 pub fn forget_permits(&self, n: usize) -> usize {
96 let removed = n.min(self.permits.get());
97 self.permits.set(self.permits.get() - removed);
98 removed
99 }
100
101 pub fn acquire(&self) -> Acquire<'_> {
106 self.acquire_many(1)
107 }
108
109 #[track_caller]
120 pub fn acquire_many(&self, n: u32) -> Acquire<'_> {
121 Acquire {
122 sem: self,
123 n: checked_permits(n),
124 key: None,
125 }
126 }
127
128 pub fn try_acquire(&self) -> Result<SemaphorePermit<'_>, TryAcquireError> {
130 self.try_acquire_many(1)
131 }
132
133 #[track_caller]
140 pub fn try_acquire_many(&self, n: u32) -> Result<SemaphorePermit<'_>, TryAcquireError> {
141 let permits = checked_permits(n);
142 if self.closed.get() {
143 return Err(TryAcquireError::Closed);
144 }
145 if !self.waiters.is_empty() || self.permits.get() < permits {
146 return Err(TryAcquireError::NoPermits);
147 }
148 self.permits.set(self.permits.get() - permits);
149 Ok(SemaphorePermit { sem: self, permits })
150 }
151
152 pub fn close(&self) {
160 if self.closed.replace(true) {
161 return;
162 }
163 while let Some(waker) = self.waiters.close_front() {
164 if let Some(waker) = waker {
165 waker.wake();
166 }
167 }
168 }
169
170 pub fn is_closed(&self) -> bool {
172 self.closed.get()
173 }
174
175 pub(crate) fn release(&self, permits: usize) {
177 self.permits.set(self.permits.get().saturating_add(permits));
178 self.serve();
179 }
180
181 fn serve(&self) {
184 if self.closed.get() {
185 return;
186 }
187 while let Some((need, waker)) = self.waiters.grant_front_if(self.permits.get()) {
188 self.permits.set(self.permits.get() - need);
189 if let Some(waker) = waker {
190 waker.wake();
191 }
192 }
193 }
194}
195
196#[expect(
198 clippy::panic,
199 reason = "documented under `# Panics` of the calls that take permits"
200)]
201#[track_caller]
202fn checked_permits(n: u32) -> usize {
203 match usize::try_from(n) {
204 Ok(permits) if permits <= Semaphore::MAX_PERMITS => permits,
205 _ => panic!("a request exceeds Semaphore::MAX_PERMITS"),
206 }
207}
208
209impl fmt::Debug for Semaphore {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 f.debug_struct("Semaphore")
212 .field("available_permits", &self.available_permits())
213 .field("closed", &self.is_closed())
214 .finish()
215 }
216}
217
218#[must_use = "dropping a permit returns it at once"]
220pub struct SemaphorePermit<'a> {
221 sem: &'a Semaphore,
222 permits: usize,
223}
224
225impl<'a> SemaphorePermit<'a> {
226 pub(crate) fn new(sem: &'a Semaphore, permits: usize) -> Self {
227 Self { sem, permits }
228 }
229
230 pub fn forget(mut self) {
232 self.permits = 0;
233 }
234
235 pub fn num_permits(&self) -> usize {
237 self.permits
238 }
239
240 #[track_caller]
246 pub fn merge(&mut self, mut other: Self) {
247 assert!(
248 core::ptr::eq(self.sem, other.sem),
249 "merging permits from different semaphore instances"
250 );
251 self.permits += other.permits;
253 other.permits = 0;
254 }
255}
256
257impl Drop for SemaphorePermit<'_> {
258 fn drop(&mut self) {
259 if self.permits > 0 {
260 self.sem.release(self.permits);
261 }
262 }
263}
264
265impl fmt::Debug for SemaphorePermit<'_> {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 f.debug_struct("SemaphorePermit")
268 .field("permits", &self.permits)
269 .finish()
270 }
271}
272
273#[must_use = "futures do nothing unless polled"]
279pub struct Acquire<'a> {
280 sem: &'a Semaphore,
281 n: usize,
282 key: Option<Key>,
283}
284
285impl Acquire<'_> {
286 #[inline]
290 pub(crate) fn cancel(&mut self) {
291 if self.key.is_some() {
292 self.leave_line();
293 }
294 }
295
296 #[inline(never)]
298 fn leave_line(&mut self) {
299 let Some(key) = self.key.take() else {
300 return;
301 };
302 let (state, was_front, waker) = self.sem.waiters.cancel(key);
303 drop(waker);
304 match state {
305 State::Waiting if was_front => self.sem.serve(),
306 State::Granted => self.sem.release(self.n),
307 _ => {}
308 }
309 }
310}
311
312impl<'a> Future for Acquire<'a> {
313 type Output = Result<SemaphorePermit<'a>, AcquireError>;
314
315 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
316 let this = self.get_mut();
317 let sem = this.sem;
318 if let Some(key) = this.key {
319 match sem.waiters.refresh(key, cx.waker()) {
320 State::Waiting => return Poll::Pending,
321 State::Granted => {
322 sem.waiters.take(key);
323 this.key = None;
324 return Poll::Ready(Ok(SemaphorePermit::new(sem, this.n)));
325 }
326 State::Closed => {
327 sem.waiters.take(key);
328 this.key = None;
329 return Poll::Ready(Err(AcquireError::closed()));
330 }
331 State::Free => this.key = None,
332 }
333 }
334 if crate::coop::exhausted(cx.waker()) {
335 return Poll::Pending;
336 }
337 if sem.closed.get() {
338 crate::coop::spent_one();
339 return Poll::Ready(Err(AcquireError::closed()));
340 }
341 if sem.waiters.is_empty() && sem.permits.get() >= this.n {
342 sem.permits.set(sem.permits.get() - this.n);
343 crate::coop::spent_one();
344 return Poll::Ready(Ok(SemaphorePermit::new(sem, this.n)));
345 }
346 this.key = Some(sem.waiters.push(this.n, cx.waker().clone()));
347 Poll::Pending
348 }
349}
350
351impl Drop for Acquire<'_> {
352 fn drop(&mut self) {
353 self.cancel();
354 }
355}
356
357impl fmt::Debug for Acquire<'_> {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 f.debug_struct("Acquire")
360 .field("permits", &self.n)
361 .field("waiting", &self.key.is_some())
362 .finish()
363 }
364}