zephyr/embassy/
executor.rs

1//! An embassy executor tailored for Zephyr
2
3use core::marker::PhantomData;
4
5use crate::sys::sync::Semaphore;
6use crate::time::Forever;
7use embassy_executor::{raw, Spawner};
8
9/// Zephyr-thread based executor.
10pub struct Executor {
11    inner: Option<raw::Executor>,
12    poll_needed: Semaphore,
13    not_send: PhantomData<*mut ()>,
14}
15
16impl Executor {
17    /// Create a new Executor.
18    pub fn new() -> Self {
19        Self {
20            inner: None,
21            poll_needed: Semaphore::new(0, 1),
22            not_send: PhantomData,
23        }
24    }
25
26    /// Run the executor.
27    pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
28        let context = self as *mut _ as *mut ();
29        self.inner.replace(raw::Executor::new(context));
30        let inner = self.inner.as_mut().unwrap();
31        init(inner.spawner());
32
33        loop {
34            let _ = self.poll_needed.take(Forever);
35            unsafe {
36                // The raw executor's poll only runs things that were queued _before_ this poll
37                // itself is actually run. This means, specifically, that if the polled execution
38                // causes this, or other threads to enqueue, this will return without running them.
39                // `__pender` _will_ be called, so the next time around the semaphore will be taken.
40                inner.poll();
41            }
42        }
43    }
44}
45
46impl Default for Executor {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52#[export_name = "__pender"]
53fn __pender(context: *mut ()) {
54    unsafe {
55        let this = context as *const Executor;
56        (*this).poll_needed.give();
57    }
58}