diff options
| author | 1-rafael-1 <[email protected]> | 2025-09-15 20:07:18 +0200 |
|---|---|---|
| committer | 1-rafael-1 <[email protected]> | 2025-09-15 20:07:18 +0200 |
| commit | 6bb3d2c0720fa082f27d3cdb70f516058497ec87 (patch) | |
| tree | 5a1e255cff999b00800f203b91a759c720c973e5 /embassy-executor-timer-queue | |
| parent | eb685574601d98c44faed9a3534d056199b46e20 (diff) | |
| parent | 92a6fd2946f2cbb15359290f68aa360953da2ff7 (diff) | |
Merge branch 'main' into rp2040-rtc-alarm
Diffstat (limited to 'embassy-executor-timer-queue')
| -rw-r--r-- | embassy-executor-timer-queue/CHANGELOG.md | 10 | ||||
| -rw-r--r-- | embassy-executor-timer-queue/Cargo.toml | 41 | ||||
| -rw-r--r-- | embassy-executor-timer-queue/README.md | 10 | ||||
| -rw-r--r-- | embassy-executor-timer-queue/src/lib.rs | 104 |
4 files changed, 165 insertions, 0 deletions
diff --git a/embassy-executor-timer-queue/CHANGELOG.md b/embassy-executor-timer-queue/CHANGELOG.md new file mode 100644 index 000000000..b4a462b66 --- /dev/null +++ b/embassy-executor-timer-queue/CHANGELOG.md | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # Changelog for embassy-executor-timer-queue | ||
| 2 | |||
| 3 | All notable changes to this project will be documented in this file. | ||
| 4 | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
| 7 | |||
| 8 | ## 0.1.0 - 2025-08-25 | ||
| 9 | |||
| 10 | - Initial implementation | ||
diff --git a/embassy-executor-timer-queue/Cargo.toml b/embassy-executor-timer-queue/Cargo.toml new file mode 100644 index 000000000..a0ac44420 --- /dev/null +++ b/embassy-executor-timer-queue/Cargo.toml | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-executor-timer-queue" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | description = "Timer queue item and interface between embassy-executor and timer queues" | ||
| 6 | repository = "https://github.com/embassy-rs/embassy" | ||
| 7 | documentation = "https://docs.embassy.dev/embassy-executor-timer-queue" | ||
| 8 | readme = "README.md" | ||
| 9 | license = "MIT OR Apache-2.0" | ||
| 10 | categories = [ | ||
| 11 | "embedded", | ||
| 12 | "no-std", | ||
| 13 | "concurrency", | ||
| 14 | "asynchronous", | ||
| 15 | ] | ||
| 16 | |||
| 17 | [dependencies] | ||
| 18 | |||
| 19 | [features] | ||
| 20 | #! ### Timer Queue Item Size | ||
| 21 | #! Sets the size of the timer items. | ||
| 22 | |||
| 23 | ## 4 words | ||
| 24 | timer-item-size-4-words = [] | ||
| 25 | |||
| 26 | ## 6 words | ||
| 27 | timer-item-size-6-words = [] | ||
| 28 | |||
| 29 | ## 8 words | ||
| 30 | timer-item-size-8-words = [] | ||
| 31 | |||
| 32 | [package.metadata.embassy_docs] | ||
| 33 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-timer-queue-v$VERSION/embassy-executor-timer-queue/src/" | ||
| 34 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor-timer-queue/src/" | ||
| 35 | target = "x86_64-unknown-linux-gnu" | ||
| 36 | |||
| 37 | [package.metadata.embassy] | ||
| 38 | build = [ | ||
| 39 | {target = "thumbv7em-none-eabi", features = []}, | ||
| 40 | {target = "thumbv6m-none-eabi", features = []}, | ||
| 41 | ] | ||
diff --git a/embassy-executor-timer-queue/README.md b/embassy-executor-timer-queue/README.md new file mode 100644 index 000000000..602aca7b1 --- /dev/null +++ b/embassy-executor-timer-queue/README.md | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # embassy-executor-time-queue | ||
| 2 | |||
| 3 | This crate defines the timer queue item that embassy-executor provides, and a way to access it, for | ||
| 4 | executor-integrated timer queues. The crate decouples the release cycle of embassy-executor from | ||
| 5 | that of the queue implementations'. | ||
| 6 | |||
| 7 | As a HAL implementer, you only need to depend on this crate if you want to implement executor-integrated | ||
| 8 | timer queues yourself, without using [`embassy-time-queue-utils`](https://crates.io/crates/embassy-time-queue-utils). | ||
| 9 | |||
| 10 | As a HAL user, you should not need to depend on this crate. | ||
diff --git a/embassy-executor-timer-queue/src/lib.rs b/embassy-executor-timer-queue/src/lib.rs new file mode 100644 index 000000000..de94e3faf --- /dev/null +++ b/embassy-executor-timer-queue/src/lib.rs | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | //! Timer queue item for embassy-executor integrated timer queues | ||
| 2 | //! | ||
| 3 | //! `embassy-executor` provides the memory needed to implement integrated timer queues. This crate | ||
| 4 | //! exists to separate that memory from `embassy-executor` itself, to decouple the timer queue's | ||
| 5 | //! release cycle from `embassy-executor`. | ||
| 6 | //! | ||
| 7 | //! This crate contains two things: | ||
| 8 | //! - [`TimerQueueItem`]: The item type that can be requested from the executor. The size of this | ||
| 9 | //! type can be configured using the `timer-item-size-N-words` Cargo features. | ||
| 10 | //! - The expectation that `extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &mut TimerQueueItem` | ||
| 11 | //! is implemented (by `embassy-executor`, most likely). This function must return a mutable | ||
| 12 | //! reference to the `TimerQueueItem` associated with the given waker. | ||
| 13 | //! | ||
| 14 | //! As a queue implementor, you will need to choose one of the `timer-item-size-N-words` features to | ||
| 15 | //! select a queue item size. You can then define your own item type, which must be | ||
| 16 | //! `#[repr(align(8))]` (or less) and must fit into the size you selected. | ||
| 17 | //! | ||
| 18 | //! You can access the `TimerQueueItem` from a `Waker` using the [`from_embassy_waker`](TimerQueueItem::from_embassy_waker) | ||
| 19 | //! method. You can then use the [`as_ref`](TimerQueueItem::as_ref) and [`as_mut`](TimerQueueItem::as_mut) | ||
| 20 | //! methods to reinterpret the data stored in the item as your custom item type. | ||
| 21 | #![no_std] | ||
| 22 | |||
| 23 | use core::task::Waker; | ||
| 24 | |||
| 25 | const ITEM_WORDS: usize = if cfg!(feature = "timer-item-size-8-words") { | ||
| 26 | 8 | ||
| 27 | } else if cfg!(feature = "timer-item-size-6-words") { | ||
| 28 | 6 | ||
| 29 | } else if cfg!(feature = "timer-item-size-4-words") { | ||
| 30 | 4 | ||
| 31 | } else { | ||
| 32 | 0 | ||
| 33 | }; | ||
| 34 | |||
| 35 | /// The timer queue item provided by the executor. | ||
| 36 | /// | ||
| 37 | /// This type is opaque, it only provides the raw storage for a queue item. The queue implementation | ||
| 38 | /// is responsible for reinterpreting the contents of the item using [`TimerQueueItem::as_ref`] and | ||
| 39 | /// [`TimerQueueItem::as_mut`]. | ||
| 40 | #[repr(align(8))] | ||
| 41 | pub struct TimerQueueItem { | ||
| 42 | data: [usize; ITEM_WORDS], | ||
| 43 | } | ||
| 44 | |||
| 45 | impl TimerQueueItem { | ||
| 46 | /// Creates a new, zero-initialized `TimerQueueItem`. | ||
| 47 | pub const fn new() -> Self { | ||
| 48 | Self { data: [0; ITEM_WORDS] } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Retrieves the `TimerQueueItem` reference that belongs to the task of the waker. | ||
| 52 | /// | ||
| 53 | /// Panics if called with a non-embassy waker. | ||
| 54 | /// | ||
| 55 | /// # Safety | ||
| 56 | /// | ||
| 57 | /// The caller must ensure they are not violating Rust's aliasing rules - it is not allowed | ||
| 58 | /// to use this method to create multiple mutable references to the same `TimerQueueItem` at | ||
| 59 | /// the same time. | ||
| 60 | /// | ||
| 61 | /// This function must only be called in the context of a timer queue implementation. | ||
| 62 | pub unsafe fn from_embassy_waker(waker: &Waker) -> &'static mut Self { | ||
| 63 | unsafe extern "Rust" { | ||
| 64 | // Waker -> TimerQueueItem, validates that Waker is an embassy Waker. | ||
| 65 | fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem; | ||
| 66 | } | ||
| 67 | unsafe { __embassy_time_queue_item_from_waker(waker) } | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Access the data as a reference to a type `T`. | ||
| 71 | /// | ||
| 72 | /// Safety: | ||
| 73 | /// | ||
| 74 | /// - The type must be valid when zero-initialized. | ||
| 75 | /// - The timer queue should only be interpreted as a single type `T` during its lifetime. | ||
| 76 | pub unsafe fn as_ref<T>(&self) -> &T { | ||
| 77 | const { validate::<T>() } | ||
| 78 | unsafe { &*(self.data.as_ptr() as *const T) } | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Access the data as a reference to a type `T`. | ||
| 82 | /// | ||
| 83 | /// Safety: | ||
| 84 | /// | ||
| 85 | /// - The type must be valid when zero-initialized. | ||
| 86 | /// - The timer queue should only be interpreted as a single type `T` during its lifetime. | ||
| 87 | pub unsafe fn as_mut<T>(&self) -> &mut T { | ||
| 88 | const { validate::<T>() } | ||
| 89 | unsafe { &mut *(self.data.as_ptr() as *mut T) } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | const fn validate<T>() { | ||
| 94 | const { | ||
| 95 | assert!( | ||
| 96 | core::mem::size_of::<TimerQueueItem>() >= core::mem::size_of::<T>(), | ||
| 97 | "embassy-executor-timer-queue item size is smaller than the requested type. Select a larger timer-item-size-N-words feature." | ||
| 98 | ); | ||
| 99 | assert!( | ||
| 100 | core::mem::align_of::<TimerQueueItem>() >= core::mem::align_of::<T>(), | ||
| 101 | "the alignment of the requested type is greater than 8" | ||
| 102 | ); | ||
| 103 | } | ||
| 104 | } | ||
