aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor-timer-queue
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor-timer-queue')
-rw-r--r--embassy-executor-timer-queue/CHANGELOG.md10
-rw-r--r--embassy-executor-timer-queue/Cargo.toml35
-rw-r--r--embassy-executor-timer-queue/README.md10
-rw-r--r--embassy-executor-timer-queue/src/lib.rs97
4 files changed, 152 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..d43e0060d
--- /dev/null
+++ b/embassy-executor-timer-queue/CHANGELOG.md
@@ -0,0 +1,10 @@
1# Changelog for embassy-time-queue-utils
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreeased
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..0db327ba9
--- /dev/null
+++ b/embassy-executor-timer-queue/Cargo.toml
@@ -0,0 +1,35 @@
1[package]
2name = "embassy-executor-timer-queue"
3version = "0.1.0"
4edition = "2021"
5description = "Timer queue item and interface between embassy-executor and timer queues"
6repository = "https://github.com/embassy-rs/embassy"
7documentation = "https://docs.embassy.dev/embassy-executor-timer-queue"
8readme = "README.md"
9license = "MIT OR Apache-2.0"
10categories = [
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
24timer-item-size-4-words = []
25
26## 6 words
27timer-item-size-6-words = []
28
29## 8 words
30timer-item-size-8-words = []
31
32[package.metadata.embassy_docs]
33src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-timer-queue-v$VERSION/embassy-executor-timer-queue/src/"
34src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor-timer-queue/src/"
35target = "x86_64-unknown-linux-gnu"
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
3This crate defines the timer queue item that embassy-executor provides, and a way to access it, for
4executor-integrated timer queues. The crate decouples the release cycle of embassy-executor from
5that of the queue implementations'.
6
7As a HAL implementer, you only need to depend on this crate if you want to implement executor-integrated
8timer queues yourself, without using [`embassy-time-queue-utils`](https://crates.io/crates/embassy-time-queue-utils).
9
10As 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..456ccaec3
--- /dev/null
+++ b/embassy-executor-timer-queue/src/lib.rs
@@ -0,0 +1,97 @@
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
23use core::task::Waker;
24
25const ITEM_SIZE: 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))]
41pub struct TimerQueueItem {
42 data: [usize; ITEM_SIZE],
43}
44
45impl TimerQueueItem {
46 /// Creates a new, zero-initialized `TimerQueueItem`.
47 pub const fn new() -> Self {
48 Self { data: [0; ITEM_SIZE] }
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 {
78 assert!(core::mem::size_of::<Self>() >= core::mem::size_of::<T>());
79 assert!(core::mem::align_of::<Self>() >= core::mem::align_of::<T>());
80 }
81 unsafe { &*(self.data.as_ptr() as *const T) }
82 }
83
84 /// Access the data as a reference to a type `T`.
85 ///
86 /// Safety:
87 ///
88 /// - The type must be valid when zero-initialized.
89 /// - The timer queue should only be interpreted as a single type `T` during its lifetime.
90 pub unsafe fn as_mut<T>(&self) -> &mut T {
91 const {
92 assert!(core::mem::size_of::<Self>() >= core::mem::size_of::<T>());
93 assert!(core::mem::align_of::<Self>() >= core::mem::align_of::<T>());
94 }
95 unsafe { &mut *(self.data.as_ptr() as *mut T) }
96 }
97}