diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-10-26 19:14:12 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-10-26 19:14:12 +0000 |
| commit | e5097a8866c071c8b986757543a723b20b67fa03 (patch) | |
| tree | 91d2c06248d17d9dfc0f22fcdba7f08eb6fd6750 /embassy-time/src/queue.rs | |
| parent | 9b86de770bccfe00ceaa6b88c51bcaba2a57eb03 (diff) | |
| parent | f9da6271cea7035b2c9f27cfe479aa81889168d1 (diff) | |
Merge #959
959: Generic, executor-agnostic queue implementation r=ivmarkov a=ivmarkov
Hopefully relatively well documented.
Implementation relies on a fixed-size `SortedLinkedList` from `heapless`. (By default, for up to 128 timer schedules, but we can lower this number to - say - 64.)
As discussed earlier, on queue overflow, the `WakerRegistration` approach is utilized, whereas the waker that is ordered first in the queue is awoken to make room for the incoming one (which might be the waker that would be awoken after all!). Wakers are compared with `Waker::will_wake`, so the queue should actually not fill up that easily, if at all.
I've left provisions for the user to manually instantiate the queue using a dedicated macro - `generic_queue!` so that users willing to adjust the queue size, or users (like me) who have to use the queue in a complex "on-top-of-RTOS-but-the-timer-driver-calling-back-from-ISR" scenario can customize the mutex that protects the queue.
The one thing I'm not completely happy with is the need to call `{ embassy_time::queue::initialize() }` early on before any futures using embassy-time are polled, which is currently on the shoulders of the user. I'm open to any ideas where we can get rid of this and do it on the first call to `_embassy_time_schedule_wake`, without introducing very complex combinations of critical sections, atomics and whatnot.
Co-authored-by: ivmarkov <[email protected]>
Co-authored-by: Dario Nieuwenhuis <[email protected]>
Diffstat (limited to 'embassy-time/src/queue.rs')
| -rw-r--r-- | embassy-time/src/queue.rs | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/embassy-time/src/queue.rs b/embassy-time/src/queue.rs new file mode 100644 index 000000000..c6f8b440a --- /dev/null +++ b/embassy-time/src/queue.rs | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | //! Timer queue implementation | ||
| 2 | //! | ||
| 3 | //! This module defines the interface a timer queue needs to implement to power the `embassy_time` module. | ||
| 4 | //! | ||
| 5 | //! # Implementing a timer queue | ||
| 6 | //! | ||
| 7 | //! - Define a struct `MyTimerQueue` | ||
| 8 | //! - Implement [`TimerQueue`] for it | ||
| 9 | //! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl). | ||
| 10 | //! | ||
| 11 | //! # Linkage details | ||
| 12 | //! | ||
| 13 | //! Check the documentation of the [`driver`](crate::driver) module for more information. | ||
| 14 | //! | ||
| 15 | //! Similarly to driver, if there is none or multiple timer queues in the crate tree, linking will fail. | ||
| 16 | //! | ||
| 17 | //! # Example | ||
| 18 | //! | ||
| 19 | //! ``` | ||
| 20 | //! use core::task::Waker; | ||
| 21 | //! | ||
| 22 | //! use embassy_time::Instant; | ||
| 23 | //! use embassy_time::queue::{TimerQueue}; | ||
| 24 | //! | ||
| 25 | //! struct MyTimerQueue{}; // not public! | ||
| 26 | //! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); | ||
| 27 | //! | ||
| 28 | //! impl TimerQueue for MyTimerQueue { | ||
| 29 | //! fn schedule_wake(&'static self, at: Instant, waker: &Waker) { | ||
| 30 | //! todo!() | ||
| 31 | //! } | ||
| 32 | //! } | ||
| 33 | //! ``` | ||
| 34 | use core::task::Waker; | ||
| 35 | |||
| 36 | use crate::Instant; | ||
| 37 | |||
| 38 | /// Timer queue | ||
| 39 | pub trait TimerQueue { | ||
| 40 | /// Schedules a waker in the queue to be awoken at moment `at`. | ||
| 41 | /// If this moment is in the past, the waker might be awoken immediately. | ||
| 42 | fn schedule_wake(&'static self, at: Instant, waker: &Waker); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Set the TimerQueue implementation. | ||
| 46 | /// | ||
| 47 | /// See the module documentation for an example. | ||
| 48 | #[macro_export] | ||
| 49 | macro_rules! timer_queue_impl { | ||
| 50 | (static $name:ident: $t: ty = $val:expr) => { | ||
| 51 | static $name: $t = $val; | ||
| 52 | |||
| 53 | #[no_mangle] | ||
| 54 | fn _embassy_time_schedule_wake(at: $crate::Instant, waker: &core::task::Waker) { | ||
| 55 | <$t as $crate::queue::TimerQueue>::schedule_wake(&$name, at, waker); | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | } | ||
