esp_hal_embassy/executor/
interrupt.rs1use core::{cell::UnsafeCell, mem::MaybeUninit};
4
5use embassy_executor::SendSpawner;
6use esp_hal::{
7 interrupt::{self, InterruptHandler, software::SoftwareInterrupt},
8 system::Cpu,
9};
10use portable_atomic::{AtomicUsize, Ordering};
11
12use super::InnerExecutor;
13
14const COUNT: usize = 3 + cfg!(not(multi_core)) as usize;
15static mut EXECUTORS: [CallbackContext; COUNT] = [const { CallbackContext::new() }; COUNT];
16
17pub struct InterruptExecutor<const SWI: u8> {
23 core: AtomicUsize,
24 executor: UnsafeCell<MaybeUninit<InnerExecutor>>,
25 interrupt: SoftwareInterrupt<'static, SWI>,
26}
27
28unsafe impl<const SWI: u8> Send for InterruptExecutor<SWI> {}
29unsafe impl<const SWI: u8> Sync for InterruptExecutor<SWI> {}
30
31struct CallbackContext {
32 raw_executor: UnsafeCell<*mut InnerExecutor>,
33}
34
35impl CallbackContext {
36 const fn new() -> Self {
37 Self {
38 raw_executor: UnsafeCell::new(core::ptr::null_mut()),
39 }
40 }
41
42 unsafe fn get(&self) -> &InnerExecutor {
46 unsafe { &**self.raw_executor.get() }
47 }
48
49 fn set(&self, executor: *mut InnerExecutor) {
50 unsafe { self.raw_executor.get().write(executor) };
51 }
52}
53
54extern "C" fn handle_interrupt<const NUM: u8>() {
55 let swi = unsafe { SoftwareInterrupt::<NUM>::steal() };
56 swi.reset();
57
58 unsafe {
59 let executor = EXECUTORS[NUM as usize].get();
61 executor.inner.poll();
62 }
63}
64
65impl<const SWI: u8> InterruptExecutor<SWI> {
66 #[inline]
69 pub const fn new(interrupt: SoftwareInterrupt<'static, SWI>) -> Self {
70 Self {
71 core: AtomicUsize::new(usize::MAX),
72 executor: UnsafeCell::new(MaybeUninit::uninit()),
73 interrupt,
74 }
75 }
76
77 pub fn start(&'static mut self, priority: interrupt::Priority) -> SendSpawner {
92 if self
93 .core
94 .compare_exchange(
95 usize::MAX,
96 Cpu::current() as usize,
97 Ordering::Acquire,
98 Ordering::Relaxed,
99 )
100 .is_err()
101 {
102 panic!("InterruptExecutor::start() called multiple times on the same executor.");
103 }
104
105 unsafe {
106 (*self.executor.get())
107 .as_mut_ptr()
108 .write(InnerExecutor::new(priority, (SWI as usize) as *mut ()));
109
110 EXECUTORS[SWI as usize].set((*self.executor.get()).as_mut_ptr());
111 }
112
113 let swi_handler = match SWI {
114 0 => handle_interrupt::<0>,
115 1 => handle_interrupt::<1>,
116 2 => handle_interrupt::<2>,
117 #[cfg(not(multi_core))]
118 3 => handle_interrupt::<3>,
119 _ => unreachable!(),
120 };
121
122 self.interrupt
123 .set_interrupt_handler(InterruptHandler::new(swi_handler, priority));
124
125 let executor = unsafe { (*self.executor.get()).assume_init_ref() };
126 executor.init();
127 executor.inner.spawner().make_send()
128 }
129
130 pub fn spawner(&'static self) -> SendSpawner {
138 if self.core.load(Ordering::Acquire) == usize::MAX {
139 panic!("InterruptExecutor::spawner() called on uninitialized executor.");
140 }
141 let executor = unsafe { (*self.executor.get()).assume_init_ref() };
142 executor.inner.spawner().make_send()
143 }
144}