ax_task/sync/
semaphore.rs1use alloc::{collections::VecDeque, sync::Arc};
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use super::RawSpinLock;
7use crate::{
8 runtime::task_runtime,
9 thread::{
10 TaskError, ThreadWakeHandle,
11 current::{self, CurrentParkStart},
12 },
13 time::MonotonicDeadline,
14};
15
16pub struct Semaphore {
22 state: RawSpinLock<SemaphoreState>,
23}
24
25struct SemaphoreState {
26 permits: usize,
27 waiters: VecDeque<Arc<SemaphoreWaiter>>,
28}
29struct SemaphoreWaiter {
30 wake: ThreadWakeHandle,
31 granted: AtomicBool,
32 handoff_complete: AtomicBool,
33}
34
35#[derive(Debug, thiserror::Error)]
37pub enum SemaphoreError {
38 #[error("semaphore wait interrupted")]
40 Interrupted,
41 #[error("semaphore wait timed out")]
43 TimedOut,
44 #[error("semaphore permit count overflow")]
46 CountOverflow,
47 #[error(transparent)]
49 Task(#[from] TaskError),
50}
51
52struct SemaphoreRegistration<'a> {
53 semaphore: &'a Semaphore,
54 waiter: Arc<SemaphoreWaiter>,
55 consumed: bool,
56}
57
58impl Semaphore {
59 pub const fn new(permits: usize) -> Self {
61 Self {
62 state: RawSpinLock::new(SemaphoreState {
63 permits,
64 waiters: VecDeque::new(),
65 }),
66 }
67 }
68
69 pub fn try_down(&self) -> bool {
71 let mut state = self.state.lock_irqsave();
72 if state.permits == 0 {
73 return false;
74 }
75 state.permits -= 1;
76 true
77 }
78
79 pub fn up(&self) -> Result<(), SemaphoreError> {
81 let _preempt = crate::runtime::lock::PreemptScope::enter();
84 let waiter = {
85 let mut state = self.state.lock_irqsave();
86 if let Some(waiter) = state.waiters.pop_front() {
87 waiter.granted.store(true, Ordering::Release);
88 Some(waiter)
89 } else {
90 state.permits = state
91 .permits
92 .checked_add(1)
93 .ok_or(SemaphoreError::CountOverflow)?;
94 None
95 }
96 };
97 if let Some(waiter) = waiter {
98 waiter.wake.wake();
101 let _state = self.state.lock_irqsave();
102 waiter.handoff_complete.store(true, Ordering::Release);
103 drop(waiter);
106 }
107 Ok(())
108 }
109
110 pub fn down(&self) -> Result<(), SemaphoreError> {
112 self.acquire(None, || false)
113 }
114
115 pub fn down_interruptible(
118 &self,
119 interrupted: impl FnMut() -> bool,
120 ) -> Result<(), SemaphoreError> {
121 self.acquire(None, interrupted)
122 }
123
124 pub fn down_until(&self, deadline: MonotonicDeadline) -> Result<(), SemaphoreError> {
126 self.acquire(Some(deadline), || false)
127 }
128
129 fn acquire(
130 &self,
131 deadline: Option<MonotonicDeadline>,
132 mut interrupted: impl FnMut() -> bool,
133 ) -> Result<(), SemaphoreError> {
134 current::validate_blocking_context()?;
135 if self.try_down() {
136 return Ok(());
137 }
138 let mut registration = SemaphoreRegistration {
139 semaphore: self,
140 consumed: false,
141 waiter: Arc::new(SemaphoreWaiter {
142 wake: current::current_thread_handle()?.wake_handle(),
143 granted: AtomicBool::new(false),
144 handoff_complete: AtomicBool::new(false),
145 }),
146 };
147 if self.enqueue(®istration.waiter) {
148 return Ok(());
149 }
150 loop {
151 let interruption = interrupted();
152 let expired =
153 deadline.is_some_and(|deadline| task_runtime::monotonic_now().reached(deadline));
154 {
155 let mut state = self.state.lock_irqsave();
156 if registration.waiter.granted.load(Ordering::Acquire) {
157 if registration.waiter.handoff_complete.load(Ordering::Acquire) {
158 registration.consumed = true;
159 return Ok(());
160 }
161 drop(state);
162 core::hint::spin_loop();
163 continue;
164 }
165 if interruption || expired {
166 registration.remove_locked(&mut state);
169 return Err(if interruption {
170 SemaphoreError::Interrupted
171 } else {
172 SemaphoreError::TimedOut
173 });
174 }
175 }
176 let CurrentParkStart::Prepared(mut park) = current::begin_current_park()? else {
177 continue;
178 };
179 let granted = {
180 let _state = self.state.lock_irqsave();
181 registration.waiter.granted.load(Ordering::Acquire)
182 };
183 if granted {
184 park.cancel()?;
185 continue;
186 }
187 if let Some(deadline) = deadline
188 && let Err(error) = arm_wait_deadline(&mut park, deadline)
189 {
190 park.cancel()?;
191 return Err(error.into());
192 }
193 park.commit()?;
194 }
195 }
196
197 fn enqueue(&self, waiter: &Arc<SemaphoreWaiter>) -> bool {
199 let mut replacement = VecDeque::new();
200 loop {
201 let mut state = self.state.lock_irqsave();
202 if state.permits != 0 {
203 state.permits -= 1;
204 return true;
205 }
206 if state.waiters.len() < state.waiters.capacity() {
207 state.waiters.push_back(Arc::clone(waiter));
208 return false;
209 }
210 if replacement.capacity() > state.waiters.len() {
211 replacement.extend(state.waiters.drain(..));
212 core::mem::swap(&mut state.waiters, &mut replacement);
213 state.waiters.push_back(Arc::clone(waiter));
214 return false;
215 }
216 let capacity = state
217 .waiters
218 .len()
219 .checked_add(1)
220 .expect("waiter count exhausted");
221 drop(state);
222 replacement = VecDeque::with_capacity(capacity);
224 }
225 }
226}
227
228#[cfg(feature = "fault-injection")]
229static FAIL_NEXT_TIMER: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
230
231#[cfg(feature = "fault-injection")]
232pub fn fail_next_semaphore_timer_registration() {
234 FAIL_NEXT_TIMER.store(
235 current::current_thread_id()
236 .expect("timer fault probe requires a task")
237 .as_u64(),
238 Ordering::Release,
239 );
240}
241
242fn arm_wait_deadline(
243 park: &mut current::PreparedCurrentPark,
244 deadline: MonotonicDeadline,
245) -> Result<(), TaskError> {
246 #[cfg(feature = "fault-injection")]
247 if FAIL_NEXT_TIMER
248 .compare_exchange(
249 current::current_thread_id()?.as_u64(),
250 0,
251 Ordering::AcqRel,
252 Ordering::Acquire,
253 )
254 .is_ok()
255 {
256 return Err(TaskError::TimerCapacity);
257 }
258 park.arm_deadline(deadline)
259}
260
261impl SemaphoreRegistration<'_> {
262 fn remove_locked(&self, state: &mut SemaphoreState) {
263 if let Some(index) = state
264 .waiters
265 .iter()
266 .position(|waiter| Arc::ptr_eq(waiter, &self.waiter))
267 {
268 state.waiters.remove(index);
269 }
270 }
271}
272
273impl Drop for SemaphoreRegistration<'_> {
274 fn drop(&mut self) {
275 let restore = loop {
276 let mut state = self.semaphore.state.lock_irqsave();
277 self.remove_locked(&mut state);
278 let granted = self.waiter.granted.load(Ordering::Acquire);
279 if granted && !self.waiter.handoff_complete.load(Ordering::Acquire) {
280 drop(state);
281 core::hint::spin_loop();
282 continue;
283 }
284 break !self.consumed && granted;
285 };
286 if restore {
287 self.semaphore
288 .up()
289 .expect("a cancelled acquisition must return its reserved permit");
290 }
291 }
292}