aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/arch/avr.rs72
-rw-r--r--embassy-executor/src/arch/riscv32.rs2
-rw-r--r--embassy-executor/src/fmt.rs3
-rw-r--r--embassy-executor/src/lib.rs6
-rw-r--r--embassy-executor/src/raw/mod.rs39
-rw-r--r--embassy-executor/src/raw/timer_queue.rs12
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")]
2compile_error!("`executor-interrupt` is not supported with `arch-avr`.");
3
4#[cfg(feature = "executor-thread")]
5pub use thread::*;
6#[cfg(feature = "executor-thread")]
7mod 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")]
7mod thread { 7mod 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
4use core::fmt::{Debug, Display, LowerHex}; 4use 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)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]); 232pub(crate) struct Bytes<'a>(pub &'a [u8]);
234 233
235impl<'a> Debug for Bytes<'a> { 234impl<'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.
7pub(crate) mod fmt; 10pub(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}
23check_at_most_one!("arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); 26check_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;
30use core::task::{Context, Poll}; 30use core::task::{Context, Poll};
31 31
32#[cfg(feature = "integrated-timers")] 32#[cfg(feature = "integrated-timers")]
33use embassy_time::driver::{self, AlarmHandle}; 33use embassy_time_driver::AlarmHandle;
34#[cfg(feature = "integrated-timers")]
35use embassy_time::Instant;
36#[cfg(feature = "rtos-trace")] 34#[cfg(feature = "rtos-trace")]
37use rtos_trace::trace; 35use 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 {
328impl SyncExecutor { 326impl 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) {
568struct TimerQueue; 567struct TimerQueue;
569 568
570#[cfg(feature = "integrated-timers")] 569#[cfg(feature = "integrated-timers")]
571impl embassy_time::queue::TimerQueue for TimerQueue { 570impl 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")]
583embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); 582embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
583
584#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))]
585const 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")]
586impl rtos_trace::RtosTraceOSCallbacks for Executor { 594impl 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 @@
1use core::cmp::min; 1use core::cmp::min;
2 2
3use embassy_time::Instant;
4
5use super::TaskRef; 3use super::TaskRef;
6use crate::raw::util::SyncUnsafeCell; 4use 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 {