aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/arch/std.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/arch/std.rs')
-rw-r--r--embassy-executor/src/arch/std.rs150
1 files changed, 83 insertions, 67 deletions
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
index 701f0eb18..4e4a178f0 100644
--- a/embassy-executor/src/arch/std.rs
+++ b/embassy-executor/src/arch/std.rs
@@ -1,84 +1,100 @@
1use std::marker::PhantomData; 1#[cfg(feature = "executor-interrupt")]
2use std::sync::{Condvar, Mutex}; 2compile_error!("`executor-interrupt` is not supported with `arch-std`.");
3 3
4use super::{raw, Spawner}; 4#[cfg(feature = "executor-thread")]
5pub use thread::*;
6#[cfg(feature = "executor-thread")]
7mod thread {
8 use std::marker::PhantomData;
9 use std::sync::{Condvar, Mutex};
5 10
6/// Single-threaded std-based executor. 11 #[cfg(feature = "nightly")]
7pub struct Executor { 12 pub use embassy_macros::main_std as main;
8 inner: raw::Executor, 13
9 not_send: PhantomData<*mut ()>, 14 use crate::raw::{Pender, PenderInner};
10 signaler: &'static Signaler, 15 use crate::{raw, Spawner};
11}
12 16
13impl Executor { 17 #[derive(Copy, Clone)]
14 /// Create a new Executor. 18 pub(crate) struct ThreadPender(&'static Signaler);
15 pub fn new() -> Self { 19
16 let signaler = &*Box::leak(Box::new(Signaler::new())); 20 impl ThreadPender {
17 Self { 21 #[allow(unused)]
18 inner: raw::Executor::new( 22 pub(crate) fn pend(self) {
19 |p| unsafe { 23 self.0.signal()
20 let s = &*(p as *const () as *const Signaler);
21 s.signal()
22 },
23 signaler as *const _ as _,
24 ),
25 not_send: PhantomData,
26 signaler,
27 } 24 }
28 } 25 }
29 26
30 /// Run the executor. 27 /// Single-threaded std-based executor.
31 /// 28 pub struct Executor {
32 /// The `init` closure is called with a [`Spawner`] that spawns tasks on 29 inner: raw::Executor,
33 /// this executor. Use it to spawn the initial task(s). After `init` returns, 30 not_send: PhantomData<*mut ()>,
34 /// the executor starts running the tasks. 31 signaler: &'static Signaler,
35 /// 32 }
36 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
37 /// for example by passing it as an argument to the initial tasks.
38 ///
39 /// This function requires `&'static mut self`. This means you have to store the
40 /// Executor instance in a place where it'll live forever and grants you mutable
41 /// access. There's a few ways to do this:
42 ///
43 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
44 /// - a `static mut` (unsafe)
45 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
46 ///
47 /// This function never returns.
48 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
49 init(self.inner.spawner());
50 33
51 loop { 34 impl Executor {
52 unsafe { self.inner.poll() }; 35 /// Create a new Executor.
53 self.signaler.wait() 36 pub fn new() -> Self {
37 let signaler = &*Box::leak(Box::new(Signaler::new()));
38 Self {
39 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))),
40 not_send: PhantomData,
41 signaler,
42 }
54 } 43 }
55 }
56}
57 44
58struct Signaler { 45 /// Run the executor.
59 mutex: Mutex<bool>, 46 ///
60 condvar: Condvar, 47 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
61} 48 /// this executor. Use it to spawn the initial task(s). After `init` returns,
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());
62 65
63impl Signaler { 66 loop {
64 fn new() -> Self { 67 unsafe { self.inner.poll() };
65 Self { 68 self.signaler.wait()
66 mutex: Mutex::new(false), 69 }
67 condvar: Condvar::new(),
68 } 70 }
69 } 71 }
70 72
71 fn wait(&self) { 73 struct Signaler {
72 let mut signaled = self.mutex.lock().unwrap(); 74 mutex: Mutex<bool>,
73 while !*signaled { 75 condvar: Condvar,
74 signaled = self.condvar.wait(signaled).unwrap();
75 }
76 *signaled = false;
77 } 76 }
78 77
79 fn signal(&self) { 78 impl Signaler {
80 let mut signaled = self.mutex.lock().unwrap(); 79 fn new() -> Self {
81 *signaled = true; 80 Self {
82 self.condvar.notify_one(); 81 mutex: Mutex::new(false),
82 condvar: Condvar::new(),
83 }
84 }
85
86 fn wait(&self) {
87 let mut signaled = self.mutex.lock().unwrap();
88 while !*signaled {
89 signaled = self.condvar.wait(signaled).unwrap();
90 }
91 *signaled = false;
92 }
93
94 fn signal(&self) {
95 let mut signaled = self.mutex.lock().unwrap();
96 *signaled = true;
97 self.condvar.notify_one();
98 }
83 } 99 }
84} 100}