aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/arch/riscv32.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/arch/riscv32.rs')
-rw-r--r--embassy-executor/src/arch/riscv32.rs133
1 files changed, 72 insertions, 61 deletions
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index e97a56cda..f66daeae4 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -1,72 +1,83 @@
1use core::marker::PhantomData; 1#[cfg(feature = "executor-interrupt")]
2use core::ptr; 2compile_error!("`executor-interrupt` is not supported with `arch-riscv32`.");
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 RISCV 11 use crate::raw::{Pender, PenderInner};
8/// 12 use crate::{raw, Spawner};
9static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
10 13
11/// RISCV32 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 RISCV
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 /// RISCV32 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 critical_section::with(|_| { 68 critical_section::with(|_| {
59 // if there is work to do, loop back to polling 69 // if there is work to do, loop back to polling
60 // TODO can we relax this? 70 // TODO can we relax this?
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 } 73 }
64 // if not, wait for interrupt 74 // if not, wait for interrupt
65 else { 75 else {
66 core::arch::asm!("wfi"); 76 core::arch::asm!("wfi");
67 } 77 }
68 }); 78 });
69 // if an interrupt occurred while waiting, it will be serviced here 79 // if an interrupt occurred while waiting, it will be serviced here
80 }
70 } 81 }
71 } 82 }
72 } 83 }