aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/arch/xtensa.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/arch/xtensa.rs')
-rw-r--r--embassy-executor/src/arch/xtensa.rs135
1 files changed, 73 insertions, 62 deletions
diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs
index 4ee0d9f78..61ea92c16 100644
--- a/embassy-executor/src/arch/xtensa.rs
+++ b/embassy-executor/src/arch/xtensa.rs
@@ -1,73 +1,84 @@
1use core::marker::PhantomData; 1#[cfg(feature = "executor-interrupt")]
2use core::ptr; 2compile_error!("`executor-interrupt` is not supported with `arch-xtensa`.");
3use core::sync::atomic::{AtomicBool, Ordering};
4 3
5use super::{raw, Spawner}; 4#[cfg(feature = "executor-thread")]
5pub use thread::*;
6#[cfg(feature = "executor-thread")]
7mod thread {
8 use core::marker::PhantomData;
9 use core::sync::atomic::{AtomicBool, Ordering};
6 10
7/// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa 11 use crate::raw::{Pender, PenderInner};
8/// 12 use crate::{raw, Spawner};
9static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
10 13
11/// Xtensa Executor 14 #[derive(Copy, Clone)]
12pub struct Executor { 15 pub(crate) struct ThreadPender;
13 inner: raw::Executor,
14 not_send: PhantomData<*mut ()>,
15}
16 16
17impl Executor { 17 impl ThreadPender {
18 /// Create a new Executor. 18 #[allow(unused)]
19 pub fn new() -> Self { 19 pub(crate) fn pend(self) {
20 Self { 20 SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
21 // use Signal_Work_Thread_Mode as substitute for local interrupt register
22 inner: raw::Executor::new(
23 |_| {
24 SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
25 },
26 ptr::null_mut(),
27 ),
28 not_send: PhantomData,
29 } 21 }
30 } 22 }
31 23
32 /// Run the executor. 24 /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
33 /// 25 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
34 /// The `init` closure is called with a [`Spawner`] that spawns tasks on 26
35 /// this executor. Use it to spawn the initial task(s). After `init` returns, 27 /// Xtensa Executor
36 /// the executor starts running the tasks. 28 pub struct Executor {
37 /// 29 inner: raw::Executor,
38 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), 30 not_send: PhantomData<*mut ()>,
39 /// for example by passing it as an argument to the initial tasks. 31 }
40 /// 32
41 /// This function requires `&'static mut self`. This means you have to store the 33 impl Executor {
42 /// Executor instance in a place where it'll live forever and grants you mutable 34 /// Create a new Executor.
43 /// access. There's a few ways to do this: 35 pub fn new() -> Self {
44 /// 36 Self {
45 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) 37 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))),
46 /// - a `static mut` (unsafe) 38 not_send: PhantomData,
47 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) 39 }
48 /// 40 }
49 /// This function never returns. 41
50 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 42 /// Run the executor.
51 init(self.inner.spawner()); 43 ///
44 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
45 /// this executor. Use it to spawn the initial task(s). After `init` returns,
46 /// the executor starts running the tasks.
47 ///
48 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
49 /// for example by passing it as an argument to the initial tasks.
50 ///
51 /// This function requires `&'static mut self`. This means you have to store the
52 /// Executor instance in a place where it'll live forever and grants you mutable
53 /// access. There's a few ways to do this:
54 ///
55 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
56 /// - a `static mut` (unsafe)
57 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
58 ///
59 /// This function never returns.
60 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
61 init(self.inner.spawner());
52 62
53 loop { 63 loop {
54 unsafe { 64 unsafe {
55 self.inner.poll(); 65 self.inner.poll();
56 // we do not care about race conditions between the load and store operations, interrupts 66 // we do not care about race conditions between the load and store operations, interrupts
57 // will only set this value to true. 67 // will only set this value to true.
58 // if there is work to do, loop back to polling 68 // if there is work to do, loop back to polling
59 // TODO can we relax this? 69 // TODO can we relax this?
60 critical_section::with(|_| { 70 critical_section::with(|_| {
61 if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { 71 if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
62 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); 72 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
63 } else { 73 } else {
64 // waiti sets the PS.INTLEVEL when slipping into sleep 74 // waiti sets the PS.INTLEVEL when slipping into sleep
65 // because critical sections in Xtensa are implemented via increasing 75 // because critical sections in Xtensa are implemented via increasing
66 // PS.INTLEVEL the critical section ends here 76 // PS.INTLEVEL the critical section ends here
67 // take care not add code after `waiti` if it needs to be inside the CS 77 // take care not add code after `waiti` if it needs to be inside the CS
68 core::arch::asm!("waiti 0"); // critical section ends here 78 core::arch::asm!("waiti 0"); // critical section ends here
69 } 79 }
70 }); 80 });
81 }
71 } 82 }
72 } 83 }
73 } 84 }