esp_radio_rtos_driver/semaphore.rs
1//! Semaphores
2//!
3//! Semaphores are synchronization primitives that allow threads to coordinate their execution.
4//! They are used to control access to a shared resource by limiting the number of threads that can
5//! access it simultaneously.
6//!
7//! esp-radio sometimes mixes up semaphores and mutexes (FreeRTOS allows this), so this crate
8//! exposes a single interface to work with both.
9//!
10//! ## Implementation
11//!
12//! Implement the `SemaphoreImplementation` trait for an object, and use the
13//! `register_semaphore_implementation` to register that implementation for esp-radio.
14//!
15//! See the [`SemaphoreImplementation`] documentation for more information.
16//!
17//! ## Usage
18//!
19//! Users should use [`SemaphoreHandle`] to interact with semaphores created by the driver
20//! implementation. Use [`SemaphoreKind`] to specify the type of semaphore or mutex to create.
21//!
22//! > Note that the only expected user of this crate is esp-radio. Application code should rely on
23//! > the platform's implementation of semaphores and mutexes.
24
25use core::ptr::NonNull;
26
27/// Pointer to an opaque semaphore created by the driver implementation.
28pub type SemaphorePtr = NonNull<()>;
29
30/// The type of semaphore or mutex to create.
31pub enum SemaphoreKind {
32 /// Counting semaphore.
33 Counting { max: u32, initial: u32 },
34
35 /// Non-recursive mutex.
36 Mutex,
37
38 /// Recursive mutex.
39 RecursiveMutex,
40}
41
42unsafe extern "Rust" {
43 fn esp_rtos_semaphore_create(kind: SemaphoreKind) -> SemaphorePtr;
44 fn esp_rtos_semaphore_delete(semaphore: SemaphorePtr);
45
46 fn esp_rtos_semaphore_take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool;
47 fn esp_rtos_semaphore_take_with_deadline(
48 semaphore: SemaphorePtr,
49 deadline_instant: Option<u64>,
50 ) -> bool;
51 fn esp_rtos_semaphore_give(semaphore: SemaphorePtr) -> bool;
52 fn esp_rtos_semaphore_try_give_from_isr(
53 semaphore: SemaphorePtr,
54 higher_prio_task_waken: Option<&mut bool>,
55 ) -> bool;
56 fn esp_rtos_semaphore_current_count(semaphore: SemaphorePtr) -> u32;
57
58 fn esp_rtos_semaphore_try_take(semaphore: SemaphorePtr) -> bool;
59 fn esp_rtos_semaphore_try_take_from_isr(
60 semaphore: SemaphorePtr,
61 higher_prio_task_waken: Option<&mut bool>,
62 ) -> bool;
63}
64
65/// A semaphore primitive.
66///
67/// The following snippet demonstrates the boilerplate necessary to implement a semaphore using the
68/// `SemaphoreImplementation` trait:
69///
70/// ```rust,no_run
71/// use esp_radio_rtos_driver::{
72/// register_semaphore_implementation,
73/// semaphore::{SemaphoreImplementation, SemaphoreKind, SemaphorePtr},
74/// };
75///
76/// struct MySemaphore {
77/// // Semaphore implementation details
78/// }
79///
80/// impl SemaphoreImplementation for MySemaphore {
81/// fn create(kind: SemaphoreKind) -> SemaphorePtr {
82/// unimplemented!()
83/// }
84///
85/// unsafe fn delete(semaphore: SemaphorePtr) {
86/// unimplemented!()
87/// }
88///
89/// unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
90/// unimplemented!()
91/// }
92///
93/// unsafe fn give(semaphore: SemaphorePtr) -> bool {
94/// unimplemented!()
95/// }
96///
97/// unsafe fn try_give_from_isr(
98/// semaphore: SemaphorePtr,
99/// higher_prio_task_waken: Option<&mut bool>,
100/// ) -> bool {
101/// unimplemented!()
102/// }
103///
104/// unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
105/// unimplemented!()
106/// }
107///
108/// unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
109/// unimplemented!()
110/// }
111///
112/// unsafe fn try_take_from_isr(
113/// semaphore: SemaphorePtr,
114/// higher_prio_task_waken: Option<&mut bool>,
115/// ) -> bool {
116/// unimplemented!()
117/// }
118/// }
119///
120/// register_semaphore_implementation!(MySemaphore);
121/// ```
122pub trait SemaphoreImplementation {
123 /// Creates a new semaphore instance.
124 ///
125 /// `kind` specifies the type of semaphore to create.
126 ///
127 /// - `SemaphoreKind::Counting` should create counting, non-recursive semaphores/mutexes.
128 /// - `SemaphoreKind::RecursiveMutex` should create recursive mutexes.
129 fn create(kind: SemaphoreKind) -> SemaphorePtr;
130
131 /// Deletes a semaphore instance.
132 ///
133 /// # Safety
134 ///
135 /// `semaphore` must be a pointer returned from [`Self::create`].
136 unsafe fn delete(semaphore: SemaphorePtr);
137
138 /// Decrements the semaphore's counter.
139 ///
140 /// If a timeout is given, this function should block until either a semaphore could be taken,
141 /// or the timeout has been reached. If no timeout is specified, the function should block
142 /// indefinitely.
143 ///
144 /// Recursive mutexes can be repeatedly taken by the same task.
145 ///
146 /// The timeout is specified in microseconds.
147 ///
148 /// This function returns `true` if the semaphore was taken, `false` if the timeout was reached.
149 ///
150 /// # Safety
151 ///
152 /// `semaphore` must be a pointer returned from [`Self::create`].
153 unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool;
154
155 /// Decrements the semaphore's counter.
156 ///
157 /// If a deadline is given, this function should block until either a semaphore could be taken,
158 /// or the deadline has been reached. If no deadline is specified, the function should block
159 /// indefinitely.
160 ///
161 /// Recursive mutexes can be repeatedly taken by the same task.
162 ///
163 /// The deadline is specified in microseconds since epoch.
164 ///
165 /// This function returns `true` if the semaphore was taken, `false` if the deadline was
166 /// reached.
167 ///
168 /// # Safety
169 ///
170 /// `semaphore` must be a pointer returned from [`Self::create`].
171 unsafe fn take_with_deadline(semaphore: SemaphorePtr, deadline_instant: Option<u64>) -> bool;
172
173 /// Increments the semaphore's counter.
174 ///
175 /// This function returns `true` if the semaphore was given, `false` if the counter is at
176 /// its maximum.
177 ///
178 /// Recursive mutexes can not be given by a task other than the one that first locked it.
179 ///
180 /// # Safety
181 ///
182 /// `semaphore` must be a pointer returned from [`Self::create`].
183 unsafe fn give(semaphore: SemaphorePtr) -> bool;
184
185 /// Attempts to increment the semaphore's counter from an ISR.
186 ///
187 /// This function returns `true` if the semaphore was given, `false` if the counter is at
188 /// its maximum.
189 ///
190 /// The `higher_prio_task_waken` parameter is an optional mutable reference to a boolean flag.
191 /// If the flag is `Some`, the implementation may set it to `true` to request a context switch.
192 ///
193 /// # Safety
194 ///
195 /// `semaphore` must be a pointer returned from [`Self::create`].
196 unsafe fn try_give_from_isr(
197 semaphore: SemaphorePtr,
198 higher_prio_task_waken: Option<&mut bool>,
199 ) -> bool;
200
201 /// Returns the semaphore's current counter value.
202 ///
203 /// # Safety
204 ///
205 /// `semaphore` must be a pointer returned from [`Self::create`].
206 unsafe fn current_count(semaphore: SemaphorePtr) -> u32;
207
208 /// Attempts to decrement the semaphore's counter.
209 ///
210 /// If the counter is zero, this function must immediately return `false`.
211 ///
212 /// # Safety
213 ///
214 /// `semaphore` must be a pointer returned from [`Self::create`].
215 unsafe fn try_take(semaphore: SemaphorePtr) -> bool;
216
217 /// Attempts to decrement the semaphore's counter from an ISR.
218 ///
219 /// If the counter is zero, this function must immediately return `false`.
220 ///
221 /// The `higher_prio_task_waken` parameter is an optional mutable reference to a boolean flag.
222 /// If the flag is `Some`, the implementation may set it to `true` to request a context switch.
223 ///
224 /// # Safety
225 ///
226 /// `semaphore` must be a pointer returned from [`Self::create`].
227 unsafe fn try_take_from_isr(
228 semaphore: SemaphorePtr,
229 higher_prio_task_waken: Option<&mut bool>,
230 ) -> bool;
231}
232
233#[macro_export]
234macro_rules! register_semaphore_implementation {
235 ($t: ty) => {
236 #[unsafe(no_mangle)]
237 #[inline]
238 fn esp_rtos_semaphore_create(
239 kind: $crate::semaphore::SemaphoreKind,
240 ) -> $crate::semaphore::SemaphorePtr {
241 <$t as $crate::semaphore::SemaphoreImplementation>::create(kind)
242 }
243
244 #[unsafe(no_mangle)]
245 #[inline]
246 fn esp_rtos_semaphore_delete(semaphore: $crate::semaphore::SemaphorePtr) {
247 unsafe { <$t as $crate::semaphore::SemaphoreImplementation>::delete(semaphore) }
248 }
249
250 #[unsafe(no_mangle)]
251 #[inline]
252 fn esp_rtos_semaphore_take(
253 semaphore: $crate::semaphore::SemaphorePtr,
254 timeout_us: Option<u32>,
255 ) -> bool {
256 unsafe {
257 <$t as $crate::semaphore::SemaphoreImplementation>::take(semaphore, timeout_us)
258 }
259 }
260
261 #[unsafe(no_mangle)]
262 #[inline]
263 fn esp_rtos_semaphore_take_with_deadline(
264 semaphore: $crate::semaphore::SemaphorePtr,
265 deadline_instant: Option<u64>,
266 ) -> bool {
267 unsafe {
268 <$t as $crate::semaphore::SemaphoreImplementation>::take_with_deadline(
269 semaphore,
270 deadline_instant,
271 )
272 }
273 }
274
275 #[unsafe(no_mangle)]
276 #[inline]
277 fn esp_rtos_semaphore_give(semaphore: $crate::semaphore::SemaphorePtr) -> bool {
278 unsafe { <$t as $crate::semaphore::SemaphoreImplementation>::give(semaphore) }
279 }
280
281 #[unsafe(no_mangle)]
282 #[inline]
283 fn esp_rtos_semaphore_try_give_from_isr(
284 semaphore: $crate::semaphore::SemaphorePtr,
285 higher_prio_task_waken: Option<&mut bool>,
286 ) -> bool {
287 unsafe {
288 <$t as $crate::semaphore::SemaphoreImplementation>::try_give_from_isr(
289 semaphore,
290 higher_prio_task_waken,
291 )
292 }
293 }
294
295 #[unsafe(no_mangle)]
296 #[inline]
297 fn esp_rtos_semaphore_current_count(semaphore: $crate::semaphore::SemaphorePtr) -> u32 {
298 unsafe { <$t as $crate::semaphore::SemaphoreImplementation>::current_count(semaphore) }
299 }
300
301 #[unsafe(no_mangle)]
302 #[inline]
303 fn esp_rtos_semaphore_try_take(semaphore: $crate::semaphore::SemaphorePtr) -> bool {
304 unsafe { <$t as $crate::semaphore::SemaphoreImplementation>::try_take(semaphore) }
305 }
306
307 #[unsafe(no_mangle)]
308 #[inline]
309 fn esp_rtos_semaphore_try_take_from_isr(
310 semaphore: $crate::semaphore::SemaphorePtr,
311 higher_prio_task_waken: Option<&mut bool>,
312 ) -> bool {
313 unsafe {
314 <$t as $crate::semaphore::SemaphoreImplementation>::try_take_from_isr(
315 semaphore,
316 higher_prio_task_waken,
317 )
318 }
319 }
320 };
321}
322
323/// Semaphore handle.
324///
325/// This handle is used to interact with semaphores created by the driver implementation.
326#[repr(transparent)]
327pub struct SemaphoreHandle(SemaphorePtr);
328impl SemaphoreHandle {
329 /// Creates a new semaphore instance.
330 ///
331 /// `kind` specifies the type of semaphore to create.
332 ///
333 /// - Use `SemaphoreKind::Counting` to create counting semaphores and non-recursive mutexes.
334 /// - Use `SemaphoreKind::RecursiveMutex` to create recursive mutexes.
335 #[inline]
336 pub fn new(kind: SemaphoreKind) -> Self {
337 let ptr = unsafe { esp_rtos_semaphore_create(kind) };
338 Self(ptr)
339 }
340
341 /// Converts this object into a pointer without dropping it.
342 #[inline]
343 pub fn leak(self) -> SemaphorePtr {
344 let ptr = self.0;
345 core::mem::forget(self);
346 ptr
347 }
348
349 /// Recovers the object from a leaked pointer.
350 ///
351 /// # Safety
352 ///
353 /// - The caller must only use pointers created using [`Self::leak`].
354 /// - The caller must ensure the pointer is not shared.
355 #[inline]
356 pub unsafe fn from_ptr(ptr: SemaphorePtr) -> Self {
357 Self(ptr)
358 }
359
360 /// Creates a reference to this object from a leaked pointer.
361 ///
362 /// This function is used in the esp-radio code to interact with the semaphore.
363 ///
364 /// # Safety
365 ///
366 /// - The caller must only use pointers created using [`Self::leak`].
367 #[inline]
368 pub unsafe fn ref_from_ptr(ptr: &SemaphorePtr) -> &Self {
369 unsafe { core::mem::transmute(ptr) }
370 }
371
372 /// Decrements the semaphore's counter.
373 ///
374 /// If a timeout is given, this function blocks until either a semaphore could be taken, or the
375 /// timeout has been reached. If no timeout is given, this function blocks until the operation
376 /// succeeds.
377 ///
378 /// This function returns `true` if the semaphore was taken, `false` if the timeout was reached.
379 #[inline]
380 pub fn take(&self, timeout_us: Option<u32>) -> bool {
381 unsafe { esp_rtos_semaphore_take(self.0, timeout_us) }
382 }
383
384 /// Decrements the semaphore's counter.
385 ///
386 /// If a deadline is given, this function blocks until either a semaphore could be taken, or the
387 /// deadline has been reached. If no deadline is given, this function blocks until the operation
388 /// succeeds.
389 ///
390 /// This function returns `true` if the semaphore was taken, `false` if the deadline was
391 /// reached.
392 #[inline]
393 pub fn take_with_deadline(&self, deadline_instant: Option<u64>) -> bool {
394 unsafe { esp_rtos_semaphore_take_with_deadline(self.0, deadline_instant) }
395 }
396
397 /// Increments the semaphore's counter.
398 ///
399 /// This function returns `true` if the semaphore was given, `false` if the counter is at its
400 /// maximum.
401 #[inline]
402 pub fn give(&self) -> bool {
403 unsafe { esp_rtos_semaphore_give(self.0) }
404 }
405
406 /// Attempts to increment the semaphore's counter from an ISR.
407 ///
408 /// If the counter is at its maximum, this function returns `false`.
409 ///
410 /// If the flag is `Some`, the implementation may set it to `true` to request a context switch.
411 #[inline]
412 pub fn try_give_from_isr(&self, higher_prio_task_waken: Option<&mut bool>) -> bool {
413 unsafe { esp_rtos_semaphore_try_give_from_isr(self.0, higher_prio_task_waken) }
414 }
415
416 /// Returns the current counter value.
417 #[inline]
418 pub fn current_count(&self) -> u32 {
419 unsafe { esp_rtos_semaphore_current_count(self.0) }
420 }
421
422 /// Attempts to decrement the semaphore's counter.
423 ///
424 /// If the counter is zero, this function returns `false`.
425 #[inline]
426 pub fn try_take(&self) -> bool {
427 unsafe { esp_rtos_semaphore_try_take(self.0) }
428 }
429
430 /// Attempts to decrement the semaphore's counter from an ISR.
431 ///
432 /// If the counter is zero, this function returns `false`.
433 ///
434 /// If a higher priority task is woken up by this operation, the `higher_prio_task_waken` flag
435 /// is set to `true`.
436 #[inline]
437 pub fn try_take_from_isr(&self, higher_prio_task_waken: Option<&mut bool>) -> bool {
438 unsafe { esp_rtos_semaphore_try_take_from_isr(self.0, higher_prio_task_waken) }
439 }
440}
441
442impl Drop for SemaphoreHandle {
443 #[inline]
444 fn drop(&mut self) {
445 unsafe { esp_rtos_semaphore_delete(self.0) };
446 }
447}
448
449unsafe impl Send for SemaphoreHandle {}
450
451#[cfg(feature = "ipc-implementations")]
452mod implementation {
453 use alloc::boxed::Box;
454 use core::ptr::NonNull;
455
456 use esp_sync::NonReentrantMutex;
457
458 use super::*;
459 use crate::{
460 ThreadPtr,
461 current_task,
462 now,
463 set_task_priority,
464 task_priority,
465 wait_queue::WaitQueueHandle,
466 };
467
468 enum SemaphoreInner {
469 Counting {
470 current: u32,
471 max: u32,
472 waiting: WaitQueueHandle,
473 },
474 Mutex {
475 recursive: bool,
476 owner: Option<ThreadPtr>,
477 original_priority: u32,
478 lock_counter: u32,
479 waiting: WaitQueueHandle,
480 },
481 }
482
483 impl SemaphoreInner {
484 fn try_take(&mut self) -> bool {
485 match self {
486 SemaphoreInner::Counting { current, .. } => {
487 if *current > 0 {
488 *current -= 1;
489 true
490 } else {
491 false
492 }
493 }
494 SemaphoreInner::Mutex {
495 recursive,
496 owner,
497 lock_counter,
498 original_priority,
499 ..
500 } => {
501 let current = current_task();
502 if let Some(owner) = *owner {
503 if owner == current && *recursive {
504 *lock_counter += 1;
505 true
506 } else {
507 // We can't lock the mutex. Make sure the mutex holder has a high enough
508 // priority to avoid priority inversion.
509 let current_priority = unsafe { task_priority(current) };
510 let owner_priority = unsafe { task_priority(owner) };
511 if owner_priority < current_priority {
512 unsafe { set_task_priority(owner, current_priority) };
513 }
514 false
515 }
516 } else {
517 *owner = Some(current);
518 *lock_counter += 1;
519 *original_priority = unsafe { task_priority(current) };
520 true
521 }
522 }
523 }
524 }
525
526 fn try_take_from_isr(&mut self) -> bool {
527 match self {
528 SemaphoreInner::Counting { current, .. } => {
529 if *current > 0 {
530 *current -= 1;
531 true
532 } else {
533 false
534 }
535 }
536 SemaphoreInner::Mutex {
537 recursive,
538 owner,
539 lock_counter,
540 ..
541 } => {
542 // In an ISR context we don't have a current task, so we can't implement
543 // priority inheritance an we have to conjure up an owner.
544 let current = NonNull::dangling();
545 if let Some(owner) = owner {
546 if *owner == current && *recursive {
547 *lock_counter += 1;
548 true
549 } else {
550 false
551 }
552 } else {
553 *owner = Some(current);
554 *lock_counter += 1;
555 true
556 }
557 }
558 }
559 }
560
561 fn try_give(&mut self) -> bool {
562 match self {
563 SemaphoreInner::Counting { current, max, .. } => {
564 if *current < *max {
565 *current += 1;
566 true
567 } else {
568 false
569 }
570 }
571 SemaphoreInner::Mutex {
572 owner,
573 lock_counter,
574 original_priority,
575 ..
576 } => {
577 let current = current_task();
578
579 if *owner == Some(current) && *lock_counter > 0 {
580 *lock_counter -= 1;
581 if *lock_counter == 0
582 && let Some(owner) = owner.take()
583 {
584 unsafe { set_task_priority(owner, *original_priority) };
585 }
586 true
587 } else {
588 false
589 }
590 }
591 }
592 }
593
594 fn try_give_from_isr(&mut self) -> bool {
595 match self {
596 SemaphoreInner::Counting { current, max, .. } => {
597 if *current < *max {
598 *current += 1;
599 true
600 } else {
601 false
602 }
603 }
604 SemaphoreInner::Mutex {
605 owner,
606 lock_counter,
607 ..
608 } => {
609 let current = NonNull::dangling();
610 if *owner == Some(current) && *lock_counter > 0 {
611 *lock_counter -= 1;
612 if *lock_counter == 0 {
613 *owner = None;
614 }
615 true
616 } else {
617 false
618 }
619 }
620 }
621 }
622
623 fn current_count(&mut self) -> u32 {
624 match self {
625 SemaphoreInner::Counting { current, .. } => *current,
626 SemaphoreInner::Mutex { .. } => {
627 panic!("RecursiveMutex does not support current_count")
628 }
629 }
630 }
631
632 fn wait_with_deadline(&mut self, deadline: Option<u64>) {
633 trace!("Semaphore wait_with_deadline - {:?}", deadline);
634 match self {
635 SemaphoreInner::Counting { waiting, .. } => waiting.wait_until(deadline),
636 SemaphoreInner::Mutex { waiting, .. } => waiting.wait_until(deadline),
637 }
638 }
639
640 fn notify(&mut self) {
641 trace!("Semaphore notify");
642 match self {
643 SemaphoreInner::Counting { waiting, .. } => waiting.notify(),
644 SemaphoreInner::Mutex { waiting, .. } => waiting.notify(),
645 }
646 }
647
648 fn notify_from_isr(&mut self, higher_prio_task_waken: Option<&mut bool>) {
649 trace!("Semaphore notify from ISR");
650 match self {
651 SemaphoreInner::Counting { waiting, .. } => {
652 waiting.notify_from_isr(higher_prio_task_waken)
653 }
654 SemaphoreInner::Mutex { waiting, .. } => {
655 waiting.notify_from_isr(higher_prio_task_waken)
656 }
657 }
658 }
659 }
660
661 /// Semaphore and mutex primitives.
662 pub struct CompatSemaphore {
663 inner: NonReentrantMutex<SemaphoreInner>,
664 }
665
666 unsafe impl Sync for CompatSemaphore {}
667
668 impl CompatSemaphore {
669 /// Create a new counting semaphore.
670 fn new_counting(initial: u32, max: u32) -> Self {
671 CompatSemaphore {
672 inner: NonReentrantMutex::new(SemaphoreInner::Counting {
673 current: initial,
674 max,
675 waiting: WaitQueueHandle::new(),
676 }),
677 }
678 }
679
680 /// Create a new mutex.
681 ///
682 /// If `recursive` is true, the mutex can be locked multiple times by the same task.
683 fn new_mutex(recursive: bool) -> Self {
684 CompatSemaphore {
685 inner: NonReentrantMutex::new(SemaphoreInner::Mutex {
686 recursive,
687 owner: None,
688 lock_counter: 0,
689 original_priority: 0,
690 waiting: WaitQueueHandle::new(),
691 }),
692 }
693 }
694
695 unsafe fn from_ptr<'a>(ptr: SemaphorePtr) -> &'a Self {
696 unsafe { ptr.cast::<Self>().as_ref() }
697 }
698
699 /// Try to take the semaphore.
700 ///
701 /// This is a non-blocking operation. The return value indicates whether the semaphore was
702 /// successfully taken.
703 fn try_take(&self) -> bool {
704 self.inner.with(|sem| sem.try_take())
705 }
706
707 /// Try to take the semaphore from an ISR.
708 ///
709 /// This is a non-blocking operation. The return value indicates whether the semaphore was
710 /// successfully taken.
711 fn try_take_from_isr(&self) -> bool {
712 self.inner.with(|sem| sem.try_take_from_isr())
713 }
714
715 /// Take the semaphore.
716 ///
717 /// This is a blocking operation.
718 ///
719 /// If the semaphore is already taken, the task will be blocked until the semaphore is
720 /// released. Recursive mutexes can be locked multiple times by the mutex owner
721 /// task.
722 fn take_with_deadline(&self, deadline: Option<u64>) -> bool {
723 let deadline_instant = deadline.unwrap_or(u64::MAX);
724 loop {
725 let taken = self.inner.with(|sem| {
726 if sem.try_take() {
727 true
728 } else {
729 // The task will go to sleep when the above critical section is released.
730 sem.wait_with_deadline(deadline);
731 false
732 }
733 });
734
735 if taken {
736 debug!("Semaphore - take - success");
737 return true;
738 }
739
740 if now() > deadline_instant {
741 debug!("Semaphore - take - timed out");
742 return false;
743 }
744 }
745 }
746
747 /// Return the current count of the semaphore.
748 fn current_count(&self) -> u32 {
749 self.inner.with(|sem| sem.current_count())
750 }
751
752 /// Unlock the semaphore.
753 fn give(&self) -> bool {
754 self.inner.with(|sem| {
755 if sem.try_give() {
756 sem.notify();
757 true
758 } else {
759 false
760 }
761 })
762 }
763
764 /// Try to unlock the semaphore from an ISR.
765 ///
766 /// The return value indicates whether the semaphore was successfully unlocked.
767 fn try_give_from_isr(&self, higher_priority_task_waken: Option<&mut bool>) -> bool {
768 self.inner.with(|sem| {
769 if sem.try_give_from_isr() {
770 sem.notify_from_isr(higher_priority_task_waken);
771 true
772 } else {
773 false
774 }
775 })
776 }
777 }
778
779 impl SemaphoreImplementation for CompatSemaphore {
780 fn create(kind: SemaphoreKind) -> SemaphorePtr {
781 let sem = Box::new(match kind {
782 SemaphoreKind::Counting { max, initial } => Self::new_counting(initial, max),
783 SemaphoreKind::Mutex => Self::new_mutex(false),
784 SemaphoreKind::RecursiveMutex => Self::new_mutex(true),
785 });
786 NonNull::from(Box::leak(sem)).cast()
787 }
788
789 unsafe fn delete(semaphore: SemaphorePtr) {
790 let sem = unsafe { Box::from_raw(semaphore.cast::<Self>().as_ptr()) };
791 core::mem::drop(sem);
792 }
793
794 unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
795 unsafe {
796 <Self as SemaphoreImplementation>::take_with_deadline(
797 semaphore,
798 timeout_us.map(|us| now() + us as u64),
799 )
800 }
801 }
802
803 unsafe fn take_with_deadline(
804 semaphore: SemaphorePtr,
805 deadline_instant: Option<u64>,
806 ) -> bool {
807 let semaphore = unsafe { Self::from_ptr(semaphore) };
808
809 semaphore.take_with_deadline(deadline_instant)
810 }
811
812 unsafe fn give(semaphore: SemaphorePtr) -> bool {
813 let semaphore = unsafe { Self::from_ptr(semaphore) };
814
815 semaphore.give()
816 }
817
818 unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
819 let semaphore = unsafe { Self::from_ptr(semaphore) };
820
821 semaphore.current_count()
822 }
823
824 unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
825 let semaphore = unsafe { Self::from_ptr(semaphore) };
826
827 semaphore.try_take()
828 }
829
830 unsafe fn try_give_from_isr(
831 semaphore: SemaphorePtr,
832 higher_priority_task_waken: Option<&mut bool>,
833 ) -> bool {
834 let semaphore = unsafe { Self::from_ptr(semaphore) };
835
836 semaphore.try_give_from_isr(higher_priority_task_waken)
837 }
838
839 unsafe fn try_take_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
840 let semaphore = unsafe { Self::from_ptr(semaphore) };
841
842 semaphore.try_take_from_isr()
843 }
844 }
845}
846
847#[cfg(feature = "ipc-implementations")]
848pub use implementation::CompatSemaphore;