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);
328
329unsafe impl Send for SemaphoreHandle {}
330unsafe impl Sync for SemaphoreHandle {}
331
332impl SemaphoreHandle {
333 /// Creates a new semaphore instance.
334 ///
335 /// `kind` specifies the type of semaphore to create.
336 ///
337 /// - Use `SemaphoreKind::Counting` to create counting semaphores and non-recursive mutexes.
338 /// - Use `SemaphoreKind::RecursiveMutex` to create recursive mutexes.
339 #[inline]
340 pub fn new(kind: SemaphoreKind) -> Self {
341 let ptr = unsafe { esp_rtos_semaphore_create(kind) };
342 Self(ptr)
343 }
344
345 /// Converts this object into a pointer without dropping it.
346 #[inline]
347 pub fn leak(self) -> SemaphorePtr {
348 let ptr = self.0;
349 core::mem::forget(self);
350 ptr
351 }
352
353 /// Recovers the object from a leaked pointer.
354 ///
355 /// # Safety
356 ///
357 /// - The caller must only use pointers created using [`Self::leak`].
358 /// - The caller must ensure the pointer is not shared.
359 #[inline]
360 pub unsafe fn from_ptr(ptr: SemaphorePtr) -> Self {
361 Self(ptr)
362 }
363
364 /// Creates a reference to this object from a leaked pointer.
365 ///
366 /// This function is used in the esp-radio code to interact with the semaphore.
367 ///
368 /// # Safety
369 ///
370 /// - The caller must only use pointers created using [`Self::leak`].
371 #[inline]
372 pub unsafe fn ref_from_ptr(ptr: &SemaphorePtr) -> &Self {
373 unsafe { core::mem::transmute(ptr) }
374 }
375
376 /// Decrements the semaphore's counter.
377 ///
378 /// If a timeout is given, this function blocks until either a semaphore could be taken, or the
379 /// timeout has been reached. If no timeout is given, this function blocks until the operation
380 /// succeeds.
381 ///
382 /// This function returns `true` if the semaphore was taken, `false` if the timeout was reached.
383 #[inline]
384 pub fn take(&self, timeout_us: Option<u32>) -> bool {
385 unsafe { esp_rtos_semaphore_take(self.0, timeout_us) }
386 }
387
388 /// Decrements the semaphore's counter.
389 ///
390 /// If a deadline is given, this function blocks until either a semaphore could be taken, or the
391 /// deadline has been reached. If no deadline is given, this function blocks until the operation
392 /// succeeds.
393 ///
394 /// This function returns `true` if the semaphore was taken, `false` if the deadline was
395 /// reached.
396 #[inline]
397 pub fn take_with_deadline(&self, deadline_instant: Option<u64>) -> bool {
398 unsafe { esp_rtos_semaphore_take_with_deadline(self.0, deadline_instant) }
399 }
400
401 /// Increments the semaphore's counter.
402 ///
403 /// This function returns `true` if the semaphore was given, `false` if the counter is at its
404 /// maximum.
405 #[inline]
406 pub fn give(&self) -> bool {
407 unsafe { esp_rtos_semaphore_give(self.0) }
408 }
409
410 /// Attempts to increment the semaphore's counter from an ISR.
411 ///
412 /// If the counter is at its maximum, this function returns `false`.
413 ///
414 /// If the flag is `Some`, the implementation may set it to `true` to request a context switch.
415 #[inline]
416 pub fn try_give_from_isr(&self, higher_prio_task_waken: Option<&mut bool>) -> bool {
417 unsafe { esp_rtos_semaphore_try_give_from_isr(self.0, higher_prio_task_waken) }
418 }
419
420 /// Returns the current counter value.
421 #[inline]
422 pub fn current_count(&self) -> u32 {
423 unsafe { esp_rtos_semaphore_current_count(self.0) }
424 }
425
426 /// Attempts to decrement the semaphore's counter.
427 ///
428 /// If the counter is zero, this function returns `false`.
429 #[inline]
430 pub fn try_take(&self) -> bool {
431 unsafe { esp_rtos_semaphore_try_take(self.0) }
432 }
433
434 /// Attempts to decrement the semaphore's counter from an ISR.
435 ///
436 /// If the counter is zero, this function returns `false`.
437 ///
438 /// If a higher priority task is woken up by this operation, the `higher_prio_task_waken` flag
439 /// is set to `true`.
440 #[inline]
441 pub fn try_take_from_isr(&self, higher_prio_task_waken: Option<&mut bool>) -> bool {
442 unsafe { esp_rtos_semaphore_try_take_from_isr(self.0, higher_prio_task_waken) }
443 }
444}
445
446impl Drop for SemaphoreHandle {
447 #[inline]
448 fn drop(&mut self) {
449 unsafe { esp_rtos_semaphore_delete(self.0) };
450 }
451}
452
453#[cfg(feature = "ipc-implementations")]
454mod implementation {
455 use alloc::boxed::Box;
456 use core::ptr::NonNull;
457
458 use esp_sync::NonReentrantMutex;
459
460 use super::*;
461 use crate::{
462 ThreadPtr,
463 current_task,
464 now,
465 set_task_priority,
466 task_priority,
467 wait_queue::WaitQueueHandle,
468 };
469
470 enum SemaphoreInner {
471 Counting {
472 current: u32,
473 max: u32,
474 waiting: WaitQueueHandle,
475 },
476 Mutex {
477 recursive: bool,
478 owner: Option<ThreadPtr>,
479 original_priority: u32,
480 lock_counter: u32,
481 waiting: WaitQueueHandle,
482 },
483 }
484
485 impl SemaphoreInner {
486 fn try_take(&mut self) -> bool {
487 match self {
488 SemaphoreInner::Counting { current, .. } => {
489 if *current > 0 {
490 *current -= 1;
491 true
492 } else {
493 false
494 }
495 }
496 SemaphoreInner::Mutex {
497 recursive,
498 owner,
499 lock_counter,
500 original_priority,
501 ..
502 } => {
503 let current = current_task();
504 if let Some(owner) = *owner {
505 if owner == current && *recursive {
506 *lock_counter += 1;
507 true
508 } else {
509 // We can't lock the mutex. Make sure the mutex holder has a high enough
510 // priority to avoid priority inversion.
511 let current_priority = unsafe { task_priority(current) };
512 let owner_priority = unsafe { task_priority(owner) };
513 if owner_priority < current_priority {
514 unsafe { set_task_priority(owner, current_priority) };
515 }
516 false
517 }
518 } else {
519 *owner = Some(current);
520 *lock_counter += 1;
521 *original_priority = unsafe { task_priority(current) };
522 true
523 }
524 }
525 }
526 }
527
528 fn try_take_from_isr(&mut self) -> bool {
529 match self {
530 SemaphoreInner::Counting { current, .. } => {
531 if *current > 0 {
532 *current -= 1;
533 true
534 } else {
535 false
536 }
537 }
538 SemaphoreInner::Mutex {
539 recursive,
540 owner,
541 lock_counter,
542 ..
543 } => {
544 // In an ISR context we don't have a current task, so we can't implement
545 // priority inheritance an we have to conjure up an owner.
546 let current = NonNull::dangling();
547 if let Some(owner) = owner {
548 if *owner == current && *recursive {
549 *lock_counter += 1;
550 true
551 } else {
552 false
553 }
554 } else {
555 *owner = Some(current);
556 *lock_counter += 1;
557 true
558 }
559 }
560 }
561 }
562
563 fn try_give(&mut self) -> bool {
564 match self {
565 SemaphoreInner::Counting { current, max, .. } => {
566 if *current < *max {
567 *current += 1;
568 true
569 } else {
570 false
571 }
572 }
573 SemaphoreInner::Mutex {
574 owner,
575 lock_counter,
576 original_priority,
577 ..
578 } => {
579 let current = current_task();
580
581 if *owner == Some(current) && *lock_counter > 0 {
582 *lock_counter -= 1;
583 if *lock_counter == 0
584 && let Some(owner) = owner.take()
585 {
586 unsafe { set_task_priority(owner, *original_priority) };
587 }
588 true
589 } else {
590 false
591 }
592 }
593 }
594 }
595
596 fn try_give_from_isr(&mut self) -> bool {
597 match self {
598 SemaphoreInner::Counting { current, max, .. } => {
599 if *current < *max {
600 *current += 1;
601 true
602 } else {
603 false
604 }
605 }
606 SemaphoreInner::Mutex {
607 owner,
608 lock_counter,
609 ..
610 } => {
611 let current = NonNull::dangling();
612 if *owner == Some(current) && *lock_counter > 0 {
613 *lock_counter -= 1;
614 if *lock_counter == 0 {
615 *owner = None;
616 }
617 true
618 } else {
619 false
620 }
621 }
622 }
623 }
624
625 fn current_count(&mut self) -> u32 {
626 match self {
627 SemaphoreInner::Counting { current, .. } => *current,
628 SemaphoreInner::Mutex { .. } => {
629 panic!("RecursiveMutex does not support current_count")
630 }
631 }
632 }
633
634 fn wait_with_deadline(&mut self, deadline: Option<u64>) {
635 trace!("Semaphore wait_with_deadline - {:?}", deadline);
636 match self {
637 SemaphoreInner::Counting { waiting, .. } => waiting.wait_until(deadline),
638 SemaphoreInner::Mutex { waiting, .. } => waiting.wait_until(deadline),
639 }
640 }
641
642 fn notify(&mut self) {
643 trace!("Semaphore notify");
644 match self {
645 SemaphoreInner::Counting { waiting, .. } => waiting.notify(),
646 SemaphoreInner::Mutex { waiting, .. } => waiting.notify(),
647 }
648 }
649
650 fn notify_from_isr(&mut self, higher_prio_task_waken: Option<&mut bool>) {
651 trace!("Semaphore notify from ISR");
652 match self {
653 SemaphoreInner::Counting { waiting, .. } => {
654 waiting.notify_from_isr(higher_prio_task_waken)
655 }
656 SemaphoreInner::Mutex { waiting, .. } => {
657 waiting.notify_from_isr(higher_prio_task_waken)
658 }
659 }
660 }
661 }
662
663 /// Semaphore and mutex primitives.
664 pub struct CompatSemaphore {
665 inner: NonReentrantMutex<SemaphoreInner>,
666 }
667
668 unsafe impl Sync for CompatSemaphore {}
669
670 impl CompatSemaphore {
671 /// Create a new counting semaphore.
672 fn new_counting(initial: u32, max: u32) -> Self {
673 CompatSemaphore {
674 inner: NonReentrantMutex::new(SemaphoreInner::Counting {
675 current: initial,
676 max,
677 waiting: WaitQueueHandle::new(),
678 }),
679 }
680 }
681
682 /// Create a new mutex.
683 ///
684 /// If `recursive` is true, the mutex can be locked multiple times by the same task.
685 fn new_mutex(recursive: bool) -> Self {
686 CompatSemaphore {
687 inner: NonReentrantMutex::new(SemaphoreInner::Mutex {
688 recursive,
689 owner: None,
690 lock_counter: 0,
691 original_priority: 0,
692 waiting: WaitQueueHandle::new(),
693 }),
694 }
695 }
696
697 unsafe fn from_ptr<'a>(ptr: SemaphorePtr) -> &'a Self {
698 unsafe { ptr.cast::<Self>().as_ref() }
699 }
700
701 /// Try to take the semaphore.
702 ///
703 /// This is a non-blocking operation. The return value indicates whether the semaphore was
704 /// successfully taken.
705 fn try_take(&self) -> bool {
706 self.inner.with(|sem| sem.try_take())
707 }
708
709 /// Try to take the semaphore from an ISR.
710 ///
711 /// This is a non-blocking operation. The return value indicates whether the semaphore was
712 /// successfully taken.
713 fn try_take_from_isr(&self) -> bool {
714 self.inner.with(|sem| sem.try_take_from_isr())
715 }
716
717 /// Take the semaphore.
718 ///
719 /// This is a blocking operation.
720 ///
721 /// If the semaphore is already taken, the task will be blocked until the semaphore is
722 /// released. Recursive mutexes can be locked multiple times by the mutex owner
723 /// task.
724 fn take_with_deadline(&self, deadline: Option<u64>) -> bool {
725 let deadline_instant = deadline.unwrap_or(u64::MAX);
726 loop {
727 let taken = self.inner.with(|sem| {
728 if sem.try_take() {
729 true
730 } else {
731 // The task will go to sleep when the above critical section is released.
732 sem.wait_with_deadline(deadline);
733 false
734 }
735 });
736
737 if taken {
738 debug!("Semaphore - take - success");
739 return true;
740 }
741
742 if now() > deadline_instant {
743 debug!("Semaphore - take - timed out");
744 return false;
745 }
746 }
747 }
748
749 /// Return the current count of the semaphore.
750 fn current_count(&self) -> u32 {
751 self.inner.with(|sem| sem.current_count())
752 }
753
754 /// Unlock the semaphore.
755 fn give(&self) -> bool {
756 self.inner.with(|sem| {
757 if sem.try_give() {
758 sem.notify();
759 true
760 } else {
761 false
762 }
763 })
764 }
765
766 /// Try to unlock the semaphore from an ISR.
767 ///
768 /// The return value indicates whether the semaphore was successfully unlocked.
769 fn try_give_from_isr(&self, higher_priority_task_waken: Option<&mut bool>) -> bool {
770 self.inner.with(|sem| {
771 if sem.try_give_from_isr() {
772 sem.notify_from_isr(higher_priority_task_waken);
773 true
774 } else {
775 false
776 }
777 })
778 }
779 }
780
781 impl SemaphoreImplementation for CompatSemaphore {
782 fn create(kind: SemaphoreKind) -> SemaphorePtr {
783 let sem = Box::new(match kind {
784 SemaphoreKind::Counting { max, initial } => Self::new_counting(initial, max),
785 SemaphoreKind::Mutex => Self::new_mutex(false),
786 SemaphoreKind::RecursiveMutex => Self::new_mutex(true),
787 });
788 NonNull::from(Box::leak(sem)).cast()
789 }
790
791 unsafe fn delete(semaphore: SemaphorePtr) {
792 let sem = unsafe { Box::from_raw(semaphore.cast::<Self>().as_ptr()) };
793 core::mem::drop(sem);
794 }
795
796 unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
797 unsafe {
798 <Self as SemaphoreImplementation>::take_with_deadline(
799 semaphore,
800 timeout_us.map(|us| now() + us as u64),
801 )
802 }
803 }
804
805 unsafe fn take_with_deadline(
806 semaphore: SemaphorePtr,
807 deadline_instant: Option<u64>,
808 ) -> bool {
809 let semaphore = unsafe { Self::from_ptr(semaphore) };
810
811 semaphore.take_with_deadline(deadline_instant)
812 }
813
814 unsafe fn give(semaphore: SemaphorePtr) -> bool {
815 let semaphore = unsafe { Self::from_ptr(semaphore) };
816
817 semaphore.give()
818 }
819
820 unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
821 let semaphore = unsafe { Self::from_ptr(semaphore) };
822
823 semaphore.current_count()
824 }
825
826 unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
827 let semaphore = unsafe { Self::from_ptr(semaphore) };
828
829 semaphore.try_take()
830 }
831
832 unsafe fn try_give_from_isr(
833 semaphore: SemaphorePtr,
834 higher_priority_task_waken: Option<&mut bool>,
835 ) -> bool {
836 let semaphore = unsafe { Self::from_ptr(semaphore) };
837
838 semaphore.try_give_from_isr(higher_priority_task_waken)
839 }
840
841 unsafe fn try_take_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
842 let semaphore = unsafe { Self::from_ptr(semaphore) };
843
844 semaphore.try_take_from_isr()
845 }
846 }
847}
848
849#[cfg(feature = "ipc-implementations")]
850pub use implementation::CompatSemaphore;