aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/thread.rs')
-rw-r--r--embassy-executor/src/thread.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/embassy-executor/src/thread.rs b/embassy-executor/src/thread.rs
new file mode 100644
index 000000000..9bbe29500
--- /dev/null
+++ b/embassy-executor/src/thread.rs
@@ -0,0 +1,80 @@
1//! Thread-mode executor.
2
3use core::marker::PhantomData;
4
5use crate::raw::{OpaqueThreadContext, Pender, PenderInner};
6use crate::{raw, Spawner};
7
8/// TODO
9// Name pending
10pub trait ThreadContext: Sized {
11 /// TODO
12 fn context(&self) -> OpaqueThreadContext;
13
14 /// TODO
15 fn wait(&mut self);
16}
17
18/// Thread mode executor, using WFE/SEV.
19///
20/// This is the simplest and most common kind of executor. It runs on
21/// thread mode (at the lowest priority level), and uses the `WFE` ARM instruction
22/// to sleep when it has no more work to do. When a task is woken, a `SEV` instruction
23/// is executed, to make the `WFE` exit from sleep and poll the task.
24///
25/// This executor allows for ultra low power consumption for chips where `WFE`
26/// triggers low-power sleep without extra steps. If your chip requires extra steps,
27/// you may use [`raw::Executor`] directly to program custom behavior.
28pub struct ThreadModeExecutor<C: ThreadContext> {
29 inner: raw::Executor,
30 context: C,
31 not_send: PhantomData<*mut ()>,
32}
33
34impl<C: ThreadContext> ThreadModeExecutor<C> {
35 /// Create a new Executor.
36 pub fn new() -> Self
37 where
38 C: Default,
39 {
40 Self::with_context(C::default())
41 }
42
43 /// Create a new Executor.
44 pub fn with_context(context: C) -> Self {
45 Self {
46 inner: raw::Executor::new(Pender(PenderInner::Thread(context.context()))),
47 context,
48 not_send: PhantomData,
49 }
50 }
51
52 /// Run the executor.
53 ///
54 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
55 /// this executor. Use it to spawn the initial task(s). After `init` returns,
56 /// the executor starts running the tasks.
57 ///
58 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
59 /// for example by passing it as an argument to the initial tasks.
60 ///
61 /// This function requires `&'static mut self`. This means you have to store the
62 /// Executor instance in a place where it'll live forever and grants you mutable
63 /// access. There's a few ways to do this:
64 ///
65 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
66 /// - a `static mut` (unsafe)
67 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
68 ///
69 /// This function never returns.
70 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
71 init(self.inner.spawner());
72
73 loop {
74 unsafe {
75 self.inner.poll();
76 self.context.wait();
77 };
78 }
79 }
80}