priority_semaphore/
semaphore.rs1use crate::{
4 error::{TryAcquireError, TryAcquireError::*},
5 lock::Lock,
6 permit::Permit,
7 queue::{WaitKey, WaitQueue},
8 waiter::{AcquireFuture, Waiter},
9};
10use alloc::sync::Arc;
11use core::{
12 sync::atomic::{AtomicUsize, Ordering},
13 task::Waker,
14};
15
16pub type Priority = i32;
21
22const CLOSED: usize = 1 << (usize::BITS - 1);
26const HAS_WAITERS: usize = 1 << (usize::BITS - 2);
27const PERMIT_MASK: usize = HAS_WAITERS - 1;
28
29pub(crate) enum RegisterResult {
30 Acquired,
31 Queued { key: WaitKey, waiter: Arc<Waiter> },
32 Closed,
33}
34
35pub struct PrioritySemaphore {
41 state: AtomicUsize,
42 pub(crate) waiters: Lock<WaitQueue>,
43 max_permits: usize,
44}
45
46impl core::fmt::Debug for PrioritySemaphore {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 f.debug_struct("PrioritySemaphore")
49 .field("available", &self.available_permits())
50 .field("queued", &self.queued())
51 .field("max_permits", &self.max_permits)
52 .field("closed", &self.is_closed())
53 .finish()
54 }
55}
56
57impl PrioritySemaphore {
58 pub const fn new(permits: usize) -> Self {
64 assert!(permits <= Self::MAX_PERMITS, "too many semaphore permits");
65 Self {
66 state: AtomicUsize::new(permits),
67 waiters: Lock::new(WaitQueue::new()),
68 max_permits: permits,
69 }
70 }
71
72 pub const MAX_PERMITS: usize = PERMIT_MASK;
74
75 pub fn acquire(self: &Arc<Self>, priority: Priority) -> AcquireFuture {
81 AcquireFuture::new(self.clone(), priority)
82 }
83
84 pub fn try_acquire(self: &Arc<Self>, _priority: Priority) -> Result<Permit, TryAcquireError> {
89 self.try_take()?;
90 Ok(Permit::new(self.clone()))
91 }
92
93 pub fn close(&self) {
98 let entries = {
99 let mut queue = self.waiters.lock();
102 let previous = self.state.fetch_or(CLOSED, Ordering::AcqRel);
103 if previous & CLOSED != 0 {
104 return;
105 }
106 let entries = queue.drain();
107 for entry in &entries {
108 entry.waiter.close();
109 }
110 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
111 entries
112 };
113
114 for entry in entries {
115 entry.waker.wake();
116 }
117 }
118
119 pub fn available_permits(&self) -> usize {
121 self.state.load(Ordering::Acquire) & PERMIT_MASK
122 }
123
124 pub fn queued(&self) -> usize {
126 self.waiters.lock().len()
127 }
128
129 pub fn is_closed(&self) -> bool {
131 self.state.load(Ordering::Acquire) & CLOSED != 0
132 }
133
134 pub(crate) fn register(&self, priority: Priority, waker: &Waker) -> RegisterResult {
135 let mut queue = self.waiters.lock();
136 let previous = self.state.fetch_or(HAS_WAITERS, Ordering::AcqRel);
137 if previous & CLOSED != 0 {
138 if queue.is_empty() {
139 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
140 }
141 return RegisterResult::Closed;
142 }
143
144 if queue.is_empty() {
147 let state = self.state.load(Ordering::Acquire);
148 debug_assert_eq!(state & CLOSED, 0);
149 if state & PERMIT_MASK != 0 {
150 match self.state.compare_exchange(
151 state,
152 state - 1,
153 Ordering::AcqRel,
154 Ordering::Acquire,
155 ) {
156 Ok(_) => {
157 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
158 return RegisterResult::Acquired;
159 }
160 Err(actual) => {
161 if actual & PERMIT_MASK != 0 {
165 let taken = self.state.compare_exchange(
166 actual,
167 actual - 1,
168 Ordering::AcqRel,
169 Ordering::Acquire,
170 );
171 if taken.is_ok() {
172 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
173 return RegisterResult::Acquired;
174 }
175 }
176 }
177 }
178 }
179 }
180
181 let waiter = Arc::new(Waiter::new());
182 let key = queue.push(priority, waiter.clone(), waker.clone());
183 RegisterResult::Queued { key, waiter }
184 }
185
186 pub(crate) fn refresh_waker(&self, key: WaitKey, waiter: &Waiter, waker: &Waker) {
187 let mut queue = self.waiters.lock();
188 if waiter.is_waiting() {
189 queue.update_waker(key, waker);
190 }
191 }
192
193 pub(crate) fn cancel_waiter(&self, key: WaitKey, waiter: &Waiter) {
194 let assigned = {
195 let mut queue = self.waiters.lock();
196 if waiter.is_waiting() {
197 let removed = queue.remove(key);
198 if removed.is_some() && queue.is_empty() {
199 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
200 }
201 false
202 } else {
203 waiter.is_assigned()
204 }
205 };
206
207 if assigned {
208 self.release_one();
209 }
210 }
211
212 pub(crate) fn release_one(&self) {
213 let mut state = self.state.load(Ordering::Acquire);
214 loop {
215 if state & HAS_WAITERS != 0 {
216 self.release_slow();
217 return;
218 }
219 debug_assert!((state & PERMIT_MASK) < self.max_permits);
220 match self.state.compare_exchange_weak(
221 state,
222 state + 1,
223 Ordering::Release,
224 Ordering::Acquire,
225 ) {
226 Ok(_) => return,
227 Err(actual) => state = actual,
228 }
229 }
230 }
231
232 pub(crate) fn try_take(&self) -> Result<(), TryAcquireError> {
233 let mut state = self.state.load(Ordering::Acquire);
234 loop {
235 if state & CLOSED != 0 {
236 return Err(Closed);
237 }
238 if state & HAS_WAITERS != 0 || state & PERMIT_MASK == 0 {
239 return Err(NoPermits);
240 }
241 match self.state.compare_exchange_weak(
242 state,
243 state - 1,
244 Ordering::Acquire,
245 Ordering::Relaxed,
246 ) {
247 Ok(_) => return Ok(()),
248 Err(actual) => state = actual,
249 }
250 }
251 }
252
253 fn release_slow(&self) {
254 let wake = {
255 let mut queue = self.waiters.lock();
256 let state = self.state.load(Ordering::Acquire);
257 if state & CLOSED == 0 {
258 if let Some(entry) = queue.pop() {
259 entry.waiter.assign();
260 if queue.is_empty() {
261 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
262 }
263 Some(entry.waker)
264 } else {
265 self.return_to_pool(&queue);
266 None
267 }
268 } else {
269 let entries = queue.drain();
272 for entry in &entries {
273 entry.waiter.close();
274 }
275 self.return_to_pool(&queue);
276 drop(queue);
277 for entry in entries {
278 entry.waker.wake();
279 }
280 return;
281 }
282 };
283 if let Some(waker) = wake {
284 waker.wake();
285 }
286 }
287
288 fn return_to_pool(&self, queue: &WaitQueue) {
289 debug_assert!(queue.is_empty());
290 self.state.fetch_and(!HAS_WAITERS, Ordering::Release);
291 let mut state = self.state.load(Ordering::Acquire);
292 loop {
293 debug_assert!((state & PERMIT_MASK) < self.max_permits);
294 match self.state.compare_exchange_weak(
295 state,
296 state + 1,
297 Ordering::Release,
298 Ordering::Acquire,
299 ) {
300 Ok(_) => return,
301 Err(actual) => state = actual,
302 }
303 }
304 }
305}