diff options
Diffstat (limited to 'embassy-executor/src')
| -rw-r--r-- | embassy-executor/src/arch/avr.rs | 72 | ||||
| -rw-r--r-- | embassy-executor/src/arch/riscv32.rs | 2 | ||||
| -rw-r--r-- | embassy-executor/src/fmt.rs | 3 | ||||
| -rw-r--r-- | embassy-executor/src/lib.rs | 6 | ||||
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 39 | ||||
| -rw-r--r-- | embassy-executor/src/raw/timer_queue.rs | 12 |
6 files changed, 108 insertions, 26 deletions
diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs new file mode 100644 index 000000000..70085d04d --- /dev/null +++ b/embassy-executor/src/arch/avr.rs | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | #[cfg(feature = "executor-interrupt")] | ||
| 2 | compile_error!("`executor-interrupt` is not supported with `arch-avr`."); | ||
| 3 | |||
| 4 | #[cfg(feature = "executor-thread")] | ||
| 5 | pub use thread::*; | ||
| 6 | #[cfg(feature = "executor-thread")] | ||
| 7 | mod thread { | ||
| 8 | use core::marker::PhantomData; | ||
| 9 | |||
| 10 | pub use embassy_executor_macros::main_avr as main; | ||
| 11 | use portable_atomic::{AtomicBool, Ordering}; | ||
| 12 | |||
| 13 | use crate::{raw, Spawner}; | ||
| 14 | |||
| 15 | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); | ||
| 16 | |||
| 17 | #[export_name = "__pender"] | ||
| 18 | fn __pender(_context: *mut ()) { | ||
| 19 | SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); | ||
| 20 | } | ||
| 21 | |||
| 22 | /// avr Executor | ||
| 23 | pub struct Executor { | ||
| 24 | inner: raw::Executor, | ||
| 25 | not_send: PhantomData<*mut ()>, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl Executor { | ||
| 29 | /// Create a new Executor. | ||
| 30 | pub fn new() -> Self { | ||
| 31 | Self { | ||
| 32 | inner: raw::Executor::new(core::ptr::null_mut()), | ||
| 33 | not_send: PhantomData, | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Run the executor. | ||
| 38 | /// | ||
| 39 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | ||
| 40 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | ||
| 41 | /// the executor starts running the tasks. | ||
| 42 | /// | ||
| 43 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||
| 44 | /// for example by passing it as an argument to the initial tasks. | ||
| 45 | /// | ||
| 46 | /// This function requires `&'static mut self`. This means you have to store the | ||
| 47 | /// Executor instance in a place where it'll live forever and grants you mutable | ||
| 48 | /// access. There's a few ways to do this: | ||
| 49 | /// | ||
| 50 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 51 | /// - a `static mut` (unsafe) | ||
| 52 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 53 | /// | ||
| 54 | /// This function never returns. | ||
| 55 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||
| 56 | init(self.inner.spawner()); | ||
| 57 | |||
| 58 | loop { | ||
| 59 | unsafe { | ||
| 60 | avr_device::interrupt::disable(); | ||
| 61 | if !SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { | ||
| 62 | avr_device::interrupt::enable(); | ||
| 63 | avr_device::asm::sleep(); | ||
| 64 | } else { | ||
| 65 | avr_device::interrupt::enable(); | ||
| 66 | self.inner.poll(); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index c56f502d3..01e63a9fd 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs | |||
| @@ -6,9 +6,9 @@ pub use thread::*; | |||
| 6 | #[cfg(feature = "executor-thread")] | 6 | #[cfg(feature = "executor-thread")] |
| 7 | mod thread { | 7 | mod thread { |
| 8 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 9 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 9 | 10 | ||
| 10 | pub use embassy_executor_macros::main_riscv as main; | 11 | pub use embassy_executor_macros::main_riscv as main; |
| 11 | use portable_atomic::{AtomicBool, Ordering}; | ||
| 12 | 12 | ||
| 13 | use crate::{raw, Spawner}; | 13 | use crate::{raw, Spawner}; |
| 14 | 14 | ||
diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs index 78e583c1c..2ac42c557 100644 --- a/embassy-executor/src/fmt.rs +++ b/embassy-executor/src/fmt.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![allow(unused_macros)] | 2 | #![allow(unused)] |
| 3 | 3 | ||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | 4 | use core::fmt::{Debug, Display, LowerHex}; |
| 5 | 5 | ||
| @@ -229,7 +229,6 @@ impl<T, E> Try for Result<T, E> { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | #[allow(unused)] | ||
| 233 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); |
| 234 | 233 | ||
| 235 | impl<'a> Debug for Bytes<'a> { | 234 | impl<'a> Debug for Bytes<'a> { |
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 4c6900a6d..6a2e493a2 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs | |||
| @@ -3,6 +3,9 @@ | |||
| 3 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 4 | #![warn(missing_docs)] | 4 | #![warn(missing_docs)] |
| 5 | 5 | ||
| 6 | //! ## Feature flags | ||
| 7 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | ||
| 8 | |||
| 6 | // This mod MUST go first, so that the others see its macros. | 9 | // This mod MUST go first, so that the others see its macros. |
| 7 | pub(crate) mod fmt; | 10 | pub(crate) mod fmt; |
| 8 | 11 | ||
| @@ -20,9 +23,10 @@ macro_rules! check_at_most_one { | |||
| 20 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); | 23 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); |
| 21 | }; | 24 | }; |
| 22 | } | 25 | } |
| 23 | check_at_most_one!("arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); | 26 | check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); |
| 24 | 27 | ||
| 25 | #[cfg(feature = "_arch")] | 28 | #[cfg(feature = "_arch")] |
| 29 | #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] | ||
| 26 | #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] | 30 | #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] |
| 27 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] | 31 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] |
| 28 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] | 32 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index b16a1c7c3..d9ea5c005 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -30,9 +30,7 @@ use core::ptr::NonNull; | |||
| 30 | use core::task::{Context, Poll}; | 30 | use core::task::{Context, Poll}; |
| 31 | 31 | ||
| 32 | #[cfg(feature = "integrated-timers")] | 32 | #[cfg(feature = "integrated-timers")] |
| 33 | use embassy_time::driver::{self, AlarmHandle}; | 33 | use embassy_time_driver::AlarmHandle; |
| 34 | #[cfg(feature = "integrated-timers")] | ||
| 35 | use embassy_time::Instant; | ||
| 36 | #[cfg(feature = "rtos-trace")] | 34 | #[cfg(feature = "rtos-trace")] |
| 37 | use rtos_trace::trace; | 35 | use rtos_trace::trace; |
| 38 | 36 | ||
| @@ -50,7 +48,7 @@ pub(crate) struct TaskHeader { | |||
| 50 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 48 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| 51 | 49 | ||
| 52 | #[cfg(feature = "integrated-timers")] | 50 | #[cfg(feature = "integrated-timers")] |
| 53 | pub(crate) expires_at: SyncUnsafeCell<Instant>, | 51 | pub(crate) expires_at: SyncUnsafeCell<u64>, |
| 54 | #[cfg(feature = "integrated-timers")] | 52 | #[cfg(feature = "integrated-timers")] |
| 55 | pub(crate) timer_queue_item: timer_queue::TimerQueueItem, | 53 | pub(crate) timer_queue_item: timer_queue::TimerQueueItem, |
| 56 | } | 54 | } |
| @@ -123,7 +121,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 123 | poll_fn: SyncUnsafeCell::new(None), | 121 | poll_fn: SyncUnsafeCell::new(None), |
| 124 | 122 | ||
| 125 | #[cfg(feature = "integrated-timers")] | 123 | #[cfg(feature = "integrated-timers")] |
| 126 | expires_at: SyncUnsafeCell::new(Instant::from_ticks(0)), | 124 | expires_at: SyncUnsafeCell::new(0), |
| 127 | #[cfg(feature = "integrated-timers")] | 125 | #[cfg(feature = "integrated-timers")] |
| 128 | timer_queue_item: timer_queue::TimerQueueItem::new(), | 126 | timer_queue_item: timer_queue::TimerQueueItem::new(), |
| 129 | }, | 127 | }, |
| @@ -164,7 +162,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 164 | this.raw.state.despawn(); | 162 | this.raw.state.despawn(); |
| 165 | 163 | ||
| 166 | #[cfg(feature = "integrated-timers")] | 164 | #[cfg(feature = "integrated-timers")] |
| 167 | this.raw.expires_at.set(Instant::MAX); | 165 | this.raw.expires_at.set(u64::MAX); |
| 168 | } | 166 | } |
| 169 | Poll::Pending => {} | 167 | Poll::Pending => {} |
| 170 | } | 168 | } |
| @@ -328,7 +326,7 @@ pub(crate) struct SyncExecutor { | |||
| 328 | impl SyncExecutor { | 326 | impl SyncExecutor { |
| 329 | pub(crate) fn new(pender: Pender) -> Self { | 327 | pub(crate) fn new(pender: Pender) -> Self { |
| 330 | #[cfg(feature = "integrated-timers")] | 328 | #[cfg(feature = "integrated-timers")] |
| 331 | let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; | 329 | let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) }; |
| 332 | 330 | ||
| 333 | Self { | 331 | Self { |
| 334 | run_queue: RunQueue::new(), | 332 | run_queue: RunQueue::new(), |
| @@ -377,18 +375,19 @@ impl SyncExecutor { | |||
| 377 | /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. | 375 | /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. |
| 378 | pub(crate) unsafe fn poll(&'static self) { | 376 | pub(crate) unsafe fn poll(&'static self) { |
| 379 | #[cfg(feature = "integrated-timers")] | 377 | #[cfg(feature = "integrated-timers")] |
| 380 | driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); | 378 | embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); |
| 381 | 379 | ||
| 382 | #[allow(clippy::never_loop)] | 380 | #[allow(clippy::never_loop)] |
| 383 | loop { | 381 | loop { |
| 384 | #[cfg(feature = "integrated-timers")] | 382 | #[cfg(feature = "integrated-timers")] |
| 385 | self.timer_queue.dequeue_expired(Instant::now(), wake_task_no_pend); | 383 | self.timer_queue |
| 384 | .dequeue_expired(embassy_time_driver::now(), wake_task_no_pend); | ||
| 386 | 385 | ||
| 387 | self.run_queue.dequeue_all(|p| { | 386 | self.run_queue.dequeue_all(|p| { |
| 388 | let task = p.header(); | 387 | let task = p.header(); |
| 389 | 388 | ||
| 390 | #[cfg(feature = "integrated-timers")] | 389 | #[cfg(feature = "integrated-timers")] |
| 391 | task.expires_at.set(Instant::MAX); | 390 | task.expires_at.set(u64::MAX); |
| 392 | 391 | ||
| 393 | if !task.state.run_dequeue() { | 392 | if !task.state.run_dequeue() { |
| 394 | // If task is not running, ignore it. This can happen in the following scenario: | 393 | // If task is not running, ignore it. This can happen in the following scenario: |
| @@ -418,7 +417,7 @@ impl SyncExecutor { | |||
| 418 | // If this is already in the past, set_alarm might return false | 417 | // If this is already in the past, set_alarm might return false |
| 419 | // In that case do another poll loop iteration. | 418 | // In that case do another poll loop iteration. |
| 420 | let next_expiration = self.timer_queue.next_expiration(); | 419 | let next_expiration = self.timer_queue.next_expiration(); |
| 421 | if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { | 420 | if embassy_time_driver::set_alarm(self.alarm, next_expiration) { |
| 422 | break; | 421 | break; |
| 423 | } | 422 | } |
| 424 | } | 423 | } |
| @@ -568,8 +567,8 @@ pub fn wake_task_no_pend(task: TaskRef) { | |||
| 568 | struct TimerQueue; | 567 | struct TimerQueue; |
| 569 | 568 | ||
| 570 | #[cfg(feature = "integrated-timers")] | 569 | #[cfg(feature = "integrated-timers")] |
| 571 | impl embassy_time::queue::TimerQueue for TimerQueue { | 570 | impl embassy_time_queue_driver::TimerQueue for TimerQueue { |
| 572 | fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { | 571 | fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) { |
| 573 | let task = waker::task_from_waker(waker); | 572 | let task = waker::task_from_waker(waker); |
| 574 | let task = task.header(); | 573 | let task = task.header(); |
| 575 | unsafe { | 574 | unsafe { |
| @@ -580,7 +579,16 @@ impl embassy_time::queue::TimerQueue for TimerQueue { | |||
| 580 | } | 579 | } |
| 581 | 580 | ||
| 582 | #[cfg(feature = "integrated-timers")] | 581 | #[cfg(feature = "integrated-timers")] |
| 583 | embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); | 582 | embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); |
| 583 | |||
| 584 | #[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] | ||
| 585 | const fn gcd(a: u64, b: u64) -> u64 { | ||
| 586 | if b == 0 { | ||
| 587 | a | ||
| 588 | } else { | ||
| 589 | gcd(b, a % b) | ||
| 590 | } | ||
| 591 | } | ||
| 584 | 592 | ||
| 585 | #[cfg(feature = "rtos-trace")] | 593 | #[cfg(feature = "rtos-trace")] |
| 586 | impl rtos_trace::RtosTraceOSCallbacks for Executor { | 594 | impl rtos_trace::RtosTraceOSCallbacks for Executor { |
| @@ -589,7 +597,8 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { | |||
| 589 | } | 597 | } |
| 590 | #[cfg(feature = "integrated-timers")] | 598 | #[cfg(feature = "integrated-timers")] |
| 591 | fn time() -> u64 { | 599 | fn time() -> u64 { |
| 592 | Instant::now().as_micros() | 600 | const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); |
| 601 | embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) | ||
| 593 | } | 602 | } |
| 594 | #[cfg(not(feature = "integrated-timers"))] | 603 | #[cfg(not(feature = "integrated-timers"))] |
| 595 | fn time() -> u64 { | 604 | fn time() -> u64 { |
diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 59a3b43f5..94a5f340b 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs | |||
| @@ -1,7 +1,5 @@ | |||
| 1 | use core::cmp::min; | 1 | use core::cmp::min; |
| 2 | 2 | ||
| 3 | use embassy_time::Instant; | ||
| 4 | |||
| 5 | use super::TaskRef; | 3 | use super::TaskRef; |
| 6 | use crate::raw::util::SyncUnsafeCell; | 4 | use crate::raw::util::SyncUnsafeCell; |
| 7 | 5 | ||
| @@ -30,7 +28,7 @@ impl TimerQueue { | |||
| 30 | 28 | ||
| 31 | pub(crate) unsafe fn update(&self, p: TaskRef) { | 29 | pub(crate) unsafe fn update(&self, p: TaskRef) { |
| 32 | let task = p.header(); | 30 | let task = p.header(); |
| 33 | if task.expires_at.get() != Instant::MAX { | 31 | if task.expires_at.get() != u64::MAX { |
| 34 | if task.state.timer_enqueue() { | 32 | if task.state.timer_enqueue() { |
| 35 | task.timer_queue_item.next.set(self.head.get()); | 33 | task.timer_queue_item.next.set(self.head.get()); |
| 36 | self.head.set(Some(p)); | 34 | self.head.set(Some(p)); |
| @@ -38,18 +36,18 @@ impl TimerQueue { | |||
| 38 | } | 36 | } |
| 39 | } | 37 | } |
| 40 | 38 | ||
| 41 | pub(crate) unsafe fn next_expiration(&self) -> Instant { | 39 | pub(crate) unsafe fn next_expiration(&self) -> u64 { |
| 42 | let mut res = Instant::MAX; | 40 | let mut res = u64::MAX; |
| 43 | self.retain(|p| { | 41 | self.retain(|p| { |
| 44 | let task = p.header(); | 42 | let task = p.header(); |
| 45 | let expires = task.expires_at.get(); | 43 | let expires = task.expires_at.get(); |
| 46 | res = min(res, expires); | 44 | res = min(res, expires); |
| 47 | expires != Instant::MAX | 45 | expires != u64::MAX |
| 48 | }); | 46 | }); |
| 49 | res | 47 | res |
| 50 | } | 48 | } |
| 51 | 49 | ||
| 52 | pub(crate) unsafe fn dequeue_expired(&self, now: Instant, on_task: impl Fn(TaskRef)) { | 50 | pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) { |
| 53 | self.retain(|p| { | 51 | self.retain(|p| { |
| 54 | let task = p.header(); | 52 | let task = p.header(); |
| 55 | if task.expires_at.get() <= now { | 53 | if task.expires_at.get() <= now { |
