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.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
new file mode 100644
index 000000000..b93ab8a79
--- /dev/null
+++ b/embassy-executor/src/arch/std.rs
@@ -0,0 +1,84 @@
1use std::marker::PhantomData;
2use std::sync::{Condvar, Mutex};
3
4use super::{raw, Spawner};
5
6/// Single-threaded std-based executor.
7pub struct Executor {
8 inner: raw::Executor,
9 not_send: PhantomData<*mut ()>,
10 signaler: &'static Signaler,
11}
12
13impl Executor {
14 /// Create a new Executor.
15 pub fn new() -> Self {
16 let signaler = &*Box::leak(Box::new(Signaler::new()));
17 Self {
18 inner: raw::Executor::new(
19 |p| unsafe {
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 }
28 }
29
30 /// Run the executor.
31 ///
32 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
33 /// this executor. Use it to spawn the initial task(s). After `init` returns,
34 /// the executor starts running the tasks.
35 ///
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 [Forever](crate::util::Forever) (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
51 loop {
52 unsafe { self.inner.poll() };
53 self.signaler.wait()
54 }
55 }
56}
57
58struct Signaler {
59 mutex: Mutex<bool>,
60 condvar: Condvar,
61}
62
63impl Signaler {
64 fn new() -> Self {
65 Self {
66 mutex: Mutex::new(false),
67 condvar: Condvar::new(),
68 }
69 }
70
71 fn wait(&self) {
72 let mut signaled = self.mutex.lock().unwrap();
73 while !*signaled {
74 signaled = self.condvar.wait(signaled).unwrap();
75 }
76 *signaled = false;
77 }
78
79 fn signal(&self) {
80 let mut signaled = self.mutex.lock().unwrap();
81 *signaled = true;
82 self.condvar.notify_one();
83 }
84}