aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/arch/riscv32.rs
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2023-08-12 16:00:18 +0200
committerDániel Buga <[email protected]>2023-08-12 18:29:56 +0200
commit675b7fb6056d8c3dfaca759b7cd373e2f4a0e111 (patch)
treeef4f786edd849f9ce82cffa3b1d58e939a4f53a7 /embassy-executor/src/arch/riscv32.rs
parent0727f8690c4684d0622547edee2cf9dc22215a9b (diff)
POC: allow custom executors
Diffstat (limited to 'embassy-executor/src/arch/riscv32.rs')
-rw-r--r--embassy-executor/src/arch/riscv32.rs100
1 files changed, 38 insertions, 62 deletions
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index ff7ec1575..5f766442d 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -1,6 +1,9 @@
1#[cfg(feature = "executor-interrupt")] 1#[cfg(feature = "executor-interrupt")]
2compile_error!("`executor-interrupt` is not supported with `arch-riscv32`."); 2compile_error!("`executor-interrupt` is not supported with `arch-riscv32`.");
3 3
4#[cfg(feature = "thread-context")]
5compile_error!("`thread-context` is not supported with `arch-riscv32`.");
6
4#[cfg(feature = "executor-thread")] 7#[cfg(feature = "executor-thread")]
5pub use thread::*; 8pub use thread::*;
6#[cfg(feature = "executor-thread")] 9#[cfg(feature = "executor-thread")]
@@ -11,77 +14,50 @@ mod thread {
11 #[cfg(feature = "nightly")] 14 #[cfg(feature = "nightly")]
12 pub use embassy_macros::main_riscv as main; 15 pub use embassy_macros::main_riscv as main;
13 16
14 use crate::raw::{Pender, PenderInner}; 17 use crate::raw::OpaqueThreadContext;
15 use crate::{raw, Spawner}; 18 use crate::thread::ThreadContext;
16
17 #[derive(Copy, Clone)]
18 pub(crate) struct ThreadPender;
19
20 impl ThreadPender {
21 #[allow(unused)]
22 pub(crate) fn pend(self) {
23 SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
24 }
25 }
26 19
27 /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV 20 /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV
28 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); 21 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
29 22
30 /// RISCV32 Executor 23 #[export_name = "__thread_mode_pender"]
31 pub struct Executor { 24 fn __thread_mode_pender(_core_id: OpaqueThreadContext) {
32 inner: raw::Executor, 25 SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
33 not_send: PhantomData<*mut ()>,
34 } 26 }
35 27
36 impl Executor { 28 /// TODO
37 /// Create a new Executor. 29 // Name pending
38 pub fn new() -> Self { 30 #[derive(Default)] // Default enables Executor::new
39 Self { 31 pub struct RiscVThreadContext {
40 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), 32 _not_send: PhantomData<*mut ()>,
41 not_send: PhantomData, 33 }
42 }
43 }
44 34
45 /// Run the executor. 35 impl ThreadContext for RiscVThreadContext {
46 /// 36 fn context(&self) -> OpaqueThreadContext {
47 /// The `init` closure is called with a [`Spawner`] that spawns tasks on 37 OpaqueThreadContext(())
48 /// this executor. Use it to spawn the initial task(s). After `init` returns, 38 }
49 /// the executor starts running the tasks.
50 ///
51 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
52 /// for example by passing it as an argument to the initial tasks.
53 ///
54 /// This function requires `&'static mut self`. This means you have to store the
55 /// Executor instance in a place where it'll live forever and grants you mutable
56 /// access. There's a few ways to do this:
57 ///
58 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
59 /// - a `static mut` (unsafe)
60 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
61 ///
62 /// This function never returns.
63 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
64 init(self.inner.spawner());
65 39
66 loop { 40 fn wait(&mut self) {
67 unsafe { 41 // We do not care about race conditions between the load and store operations,
68 self.inner.poll(); 42 // interrupts will only set this value to true.
69 // we do not care about race conditions between the load and store operations, interrupts 43 critical_section::with(|_| {
70 //will only set this value to true. 44 // if there is work to do, loop back to polling
71 critical_section::with(|_| { 45 // TODO can we relax this?
72 // if there is work to do, loop back to polling 46 if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
73 // TODO can we relax this? 47 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
74 if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
75 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
76 }
77 // if not, wait for interrupt
78 else {
79 core::arch::asm!("wfi");
80 }
81 });
82 // if an interrupt occurred while waiting, it will be serviced here
83 } 48 }
84 } 49 // if not, wait for interrupt
50 else {
51 unsafe {
52 core::arch::asm!("wfi");
53 }
54 }
55 });
56 // if an interrupt occurred while waiting, it will be serviced here
85 } 57 }
86 } 58 }
59
60 /// TODO
61 // Type alias for backwards compatibility
62 pub type Executor = crate::thread::ThreadModeExecutor<RiscVThreadContext>;
87} 63}