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