drivers/standard_library/
executor.rs

1use embassy_executor::{Spawner, raw};
2use std::boxed::Box;
3use std::marker::PhantomData;
4use std::sync::atomic::AtomicBool;
5use std::sync::{Condvar, Mutex};
6
7/// Single-threaded std-based executor.
8pub struct Executor {
9    inner: raw::Executor,
10    not_send: PhantomData<*mut ()>,
11    signaler: &'static Signaler,
12    stop: AtomicBool,
13}
14
15impl Default for Executor {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl Executor {
22    /// Create a new Executor.
23    pub fn new() -> Self {
24        let signaler = Box::leak(Box::new(Signaler::new()));
25        Self {
26            inner: raw::Executor::new(signaler as *mut Signaler as *mut ()),
27            not_send: PhantomData,
28            signaler,
29            stop: AtomicBool::new(false),
30        }
31    }
32
33    pub fn stop(&self) {
34        self.stop.store(true, std::sync::atomic::Ordering::SeqCst);
35        self.signaler.signal();
36    }
37
38    /// Get a spawner for this executor.
39    pub fn spawner(&'static self) -> Spawner {
40        self.inner.spawner()
41    }
42
43    /// Run the executor.
44    ///
45    /// The `init` closure is called with a [`Spawner`] that spawns tasks on
46    /// this executor. Use it to spawn the initial task(s). After `init` returns,
47    /// the executor starts running the tasks.
48    ///
49    /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
50    /// for example by passing it as an argument to the initial tasks.
51    ///
52    /// This function requires `&'static mut self`. This means you have to store the
53    /// Executor instance in a place where it'll live forever and grants you mutable
54    /// access. There's a few ways to do this:
55    ///
56    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
57    /// - a `static mut` (unsafe)
58    /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
59    ///
60    /// This function never returns.
61    pub fn run(&'static self, init: impl FnOnce(Spawner, &'static Self)) {
62        init(self.inner.spawner(), self);
63
64        while !self.stop.load(std::sync::atomic::Ordering::SeqCst) {
65            unsafe { self.inner.poll() };
66            self.signaler.wait();
67        }
68    }
69}
70
71struct Signaler {
72    mutex: Mutex<bool>,
73    condvar: Condvar,
74}
75
76impl Signaler {
77    fn new() -> Self {
78        Self {
79            mutex: Mutex::new(false),
80            condvar: Condvar::new(),
81        }
82    }
83
84    fn wait(&self) {
85        let mut signaled = self.mutex.lock().unwrap();
86        while !*signaled {
87            signaled = self.condvar.wait(signaled).unwrap();
88        }
89        *signaled = false;
90    }
91
92    fn signal(&self) {
93        let mut signaled = self.mutex.lock().unwrap();
94        *signaled = true;
95        self.condvar.notify_one();
96    }
97}
98
99#[macro_export]
100macro_rules! instantiate_static_executor {
101    () => {{
102        static mut __EXECUTOR: Option<$crate::standard_library::executor::Executor> = None;
103
104        unsafe {
105            if __EXECUTOR.is_none() {
106                __EXECUTOR = Some($crate::standard_library::executor::Executor::new());
107            }
108            __EXECUTOR.as_mut().expect("Executor is not initialized")
109        }
110    }};
111}
112
113pub use instantiate_static_executor;