diff options
| author | Olof <[email protected]> | 2024-12-18 01:48:25 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-12-18 01:48:25 +0100 |
| commit | 7cf96e4730964d085015320648c870a05fbaf431 (patch) | |
| tree | 04072529b62082cb66443377b589fe08169f83be /embassy-executor/src/raw/timer_queue.rs | |
| parent | 8678911028a591d72fd1d8418407b5885ed4c417 (diff) | |
| parent | 341036a8b865609767fbf9015b482ea70ed4f23f (diff) | |
Merge branch 'embassy-rs:main' into u5_adc
Diffstat (limited to 'embassy-executor/src/raw/timer_queue.rs')
| -rw-r--r-- | embassy-executor/src/raw/timer_queue.rs | 119 |
1 files changed, 58 insertions, 61 deletions
diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 94a5f340b..e52453be4 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs | |||
| @@ -1,76 +1,73 @@ | |||
| 1 | use core::cmp::min; | 1 | //! Timer queue operations. |
| 2 | |||
| 3 | use core::cell::Cell; | ||
| 2 | 4 | ||
| 3 | use super::TaskRef; | 5 | use super::TaskRef; |
| 4 | use crate::raw::util::SyncUnsafeCell; | ||
| 5 | 6 | ||
| 6 | pub(crate) struct TimerQueueItem { | 7 | #[cfg(feature = "_timer-item-payload")] |
| 7 | next: SyncUnsafeCell<Option<TaskRef>>, | 8 | macro_rules! define_opaque { |
| 8 | } | 9 | ($size:tt) => { |
| 10 | /// An opaque data type. | ||
| 11 | #[repr(align($size))] | ||
| 12 | pub struct OpaqueData { | ||
| 13 | data: [u8; $size], | ||
| 14 | } | ||
| 9 | 15 | ||
| 10 | impl TimerQueueItem { | 16 | impl OpaqueData { |
| 11 | pub const fn new() -> Self { | 17 | const fn new() -> Self { |
| 12 | Self { | 18 | Self { data: [0; $size] } |
| 13 | next: SyncUnsafeCell::new(None), | 19 | } |
| 20 | |||
| 21 | /// Access the data as a reference to a type `T`. | ||
| 22 | /// | ||
| 23 | /// Safety: | ||
| 24 | /// | ||
| 25 | /// The caller must ensure that the size of the type `T` is less than, or equal to | ||
| 26 | /// the size of the payload, and must ensure that the alignment of the type `T` is | ||
| 27 | /// less than, or equal to the alignment of the payload. | ||
| 28 | /// | ||
| 29 | /// The type must be valid when zero-initialized. | ||
| 30 | pub unsafe fn as_ref<T>(&self) -> &T { | ||
| 31 | &*(self.data.as_ptr() as *const T) | ||
| 32 | } | ||
| 14 | } | 33 | } |
| 15 | } | 34 | }; |
| 16 | } | 35 | } |
| 17 | 36 | ||
| 18 | pub(crate) struct TimerQueue { | 37 | #[cfg(feature = "timer-item-payload-size-1")] |
| 19 | head: SyncUnsafeCell<Option<TaskRef>>, | 38 | define_opaque!(1); |
| 20 | } | 39 | #[cfg(feature = "timer-item-payload-size-2")] |
| 40 | define_opaque!(2); | ||
| 41 | #[cfg(feature = "timer-item-payload-size-4")] | ||
| 42 | define_opaque!(4); | ||
| 43 | #[cfg(feature = "timer-item-payload-size-8")] | ||
| 44 | define_opaque!(8); | ||
| 21 | 45 | ||
| 22 | impl TimerQueue { | 46 | /// An item in the timer queue. |
| 23 | pub const fn new() -> Self { | 47 | pub struct TimerQueueItem { |
| 24 | Self { | 48 | /// The next item in the queue. |
| 25 | head: SyncUnsafeCell::new(None), | 49 | /// |
| 26 | } | 50 | /// If this field contains `Some`, the item is in the queue. The last item in the queue has a |
| 27 | } | 51 | /// value of `Some(dangling_pointer)` |
| 52 | pub next: Cell<Option<TaskRef>>, | ||
| 28 | 53 | ||
| 29 | pub(crate) unsafe fn update(&self, p: TaskRef) { | 54 | /// The time at which this item expires. |
| 30 | let task = p.header(); | 55 | pub expires_at: Cell<u64>, |
| 31 | if task.expires_at.get() != u64::MAX { | ||
| 32 | if task.state.timer_enqueue() { | ||
| 33 | task.timer_queue_item.next.set(self.head.get()); | ||
| 34 | self.head.set(Some(p)); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | 56 | ||
| 39 | pub(crate) unsafe fn next_expiration(&self) -> u64 { | 57 | /// Some implementation-defined, zero-initialized piece of data. |
| 40 | let mut res = u64::MAX; | 58 | #[cfg(feature = "_timer-item-payload")] |
| 41 | self.retain(|p| { | 59 | pub payload: OpaqueData, |
| 42 | let task = p.header(); | 60 | } |
| 43 | let expires = task.expires_at.get(); | ||
| 44 | res = min(res, expires); | ||
| 45 | expires != u64::MAX | ||
| 46 | }); | ||
| 47 | res | ||
| 48 | } | ||
| 49 | 61 | ||
| 50 | pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) { | 62 | unsafe impl Sync for TimerQueueItem {} |
| 51 | self.retain(|p| { | ||
| 52 | let task = p.header(); | ||
| 53 | if task.expires_at.get() <= now { | ||
| 54 | on_task(p); | ||
| 55 | false | ||
| 56 | } else { | ||
| 57 | true | ||
| 58 | } | ||
| 59 | }); | ||
| 60 | } | ||
| 61 | 63 | ||
| 62 | pub(crate) unsafe fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { | 64 | impl TimerQueueItem { |
| 63 | let mut prev = &self.head; | 65 | pub(crate) const fn new() -> Self { |
| 64 | while let Some(p) = prev.get() { | 66 | Self { |
| 65 | let task = p.header(); | 67 | next: Cell::new(None), |
| 66 | if f(p) { | 68 | expires_at: Cell::new(0), |
| 67 | // Skip to next | 69 | #[cfg(feature = "_timer-item-payload")] |
| 68 | prev = &task.timer_queue_item.next; | 70 | payload: OpaqueData::new(), |
| 69 | } else { | ||
| 70 | // Remove it | ||
| 71 | prev.set(task.timer_queue_item.next.get()); | ||
| 72 | task.state.timer_dequeue(); | ||
| 73 | } | ||
| 74 | } | 71 | } |
| 75 | } | 72 | } |
| 76 | } | 73 | } |
