diff options
Diffstat (limited to 'embassy-executor/src/lib.rs')
| -rw-r--r-- | embassy-executor/src/lib.rs | 110 |
1 files changed, 91 insertions, 19 deletions
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index f2c86d8e6..d8ac4893b 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] | 1 | #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] |
| 2 | #![cfg_attr(all(feature = "nightly", feature = "arch-xtensa"), feature(asm_experimental_arch))] | 2 | #![cfg_attr(feature = "arch-xtensa", feature(asm_experimental_arch))] |
| 3 | #![allow(clippy::new_without_default)] | 3 | #![allow(clippy::new_without_default)] |
| 4 | #![doc = include_str!("../README.md")] | 4 | #![doc = include_str!("../README.md")] |
| 5 | #![warn(missing_docs)] | 5 | #![warn(missing_docs)] |
| @@ -7,7 +7,6 @@ | |||
| 7 | // This mod MUST go first, so that the others see its macros. | 7 | // This mod MUST go first, so that the others see its macros. |
| 8 | pub(crate) mod fmt; | 8 | pub(crate) mod fmt; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "nightly")] | ||
| 11 | pub use embassy_macros::task; | 10 | pub use embassy_macros::task; |
| 12 | 11 | ||
| 13 | macro_rules! check_at_most_one { | 12 | macro_rules! check_at_most_one { |
| @@ -41,28 +40,101 @@ pub mod raw; | |||
| 41 | mod spawner; | 40 | mod spawner; |
| 42 | pub use spawner::*; | 41 | pub use spawner::*; |
| 43 | 42 | ||
| 43 | mod config { | ||
| 44 | #![allow(unused)] | ||
| 45 | include!(concat!(env!("OUT_DIR"), "/config.rs")); | ||
| 46 | } | ||
| 47 | |||
| 44 | /// Implementation details for embassy macros. | 48 | /// Implementation details for embassy macros. |
| 45 | /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. | 49 | /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. |
| 46 | #[doc(hidden)] | 50 | #[doc(hidden)] |
| 51 | #[cfg(not(feature = "nightly"))] | ||
| 47 | pub mod _export { | 52 | pub mod _export { |
| 48 | #[cfg(feature = "rtos-trace")] | 53 | use core::alloc::Layout; |
| 49 | pub use rtos_trace::trace; | 54 | use core::cell::{Cell, UnsafeCell}; |
| 50 | 55 | use core::future::Future; | |
| 51 | /// Expands the given block of code when `embassy-executor` is compiled with | 56 | use core::mem::MaybeUninit; |
| 52 | /// the `rtos-trace-interrupt` feature. | 57 | use core::ptr::null_mut; |
| 53 | #[doc(hidden)] | 58 | |
| 54 | #[macro_export] | 59 | use critical_section::{CriticalSection, Mutex}; |
| 55 | #[cfg(feature = "rtos-trace-interrupt")] | 60 | |
| 56 | macro_rules! rtos_trace_interrupt { | 61 | use crate::raw::TaskPool; |
| 57 | ($($tt:tt)*) => { $($tt)* }; | 62 | |
| 63 | struct Arena<const N: usize> { | ||
| 64 | buf: UnsafeCell<MaybeUninit<[u8; N]>>, | ||
| 65 | ptr: Mutex<Cell<*mut u8>>, | ||
| 58 | } | 66 | } |
| 59 | 67 | ||
| 60 | /// Does not expand the given block of code when `embassy-executor` is | 68 | unsafe impl<const N: usize> Sync for Arena<N> {} |
| 61 | /// compiled without the `rtos-trace-interrupt` feature. | 69 | unsafe impl<const N: usize> Send for Arena<N> {} |
| 62 | #[doc(hidden)] | 70 | |
| 63 | #[macro_export] | 71 | impl<const N: usize> Arena<N> { |
| 64 | #[cfg(not(feature = "rtos-trace-interrupt"))] | 72 | const fn new() -> Self { |
| 65 | macro_rules! rtos_trace_interrupt { | 73 | Self { |
| 66 | ($($tt:tt)*) => {}; | 74 | buf: UnsafeCell::new(MaybeUninit::uninit()), |
| 75 | ptr: Mutex::new(Cell::new(null_mut())), | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | fn alloc<T>(&'static self, cs: CriticalSection) -> &'static mut MaybeUninit<T> { | ||
| 80 | let layout = Layout::new::<T>(); | ||
| 81 | |||
| 82 | let start = self.buf.get().cast::<u8>(); | ||
| 83 | let end = unsafe { start.add(N) }; | ||
| 84 | |||
| 85 | let mut ptr = self.ptr.borrow(cs).get(); | ||
| 86 | if ptr.is_null() { | ||
| 87 | ptr = self.buf.get().cast::<u8>(); | ||
| 88 | } | ||
| 89 | |||
| 90 | let bytes_left = (end as usize) - (ptr as usize); | ||
| 91 | let align_offset = (ptr as usize).next_multiple_of(layout.align()) - (ptr as usize); | ||
| 92 | |||
| 93 | if align_offset + layout.size() > bytes_left { | ||
| 94 | panic!("embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/"); | ||
| 95 | } | ||
| 96 | |||
| 97 | let res = unsafe { ptr.add(align_offset) }; | ||
| 98 | let ptr = unsafe { ptr.add(align_offset + layout.size()) }; | ||
| 99 | |||
| 100 | self.ptr.borrow(cs).set(ptr); | ||
| 101 | |||
| 102 | unsafe { &mut *(res as *mut MaybeUninit<T>) } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static ARENA: Arena<{ crate::config::TASK_ARENA_SIZE }> = Arena::new(); | ||
| 107 | |||
| 108 | pub struct TaskPoolRef { | ||
| 109 | // type-erased `&'static mut TaskPool<F, N>` | ||
| 110 | // Needed because statics can't have generics. | ||
| 111 | ptr: Mutex<Cell<*mut ()>>, | ||
| 112 | } | ||
| 113 | unsafe impl Sync for TaskPoolRef {} | ||
| 114 | unsafe impl Send for TaskPoolRef {} | ||
| 115 | |||
| 116 | impl TaskPoolRef { | ||
| 117 | pub const fn new() -> Self { | ||
| 118 | Self { | ||
| 119 | ptr: Mutex::new(Cell::new(null_mut())), | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Get the pool for this ref, allocating it from the arena the first time. | ||
| 124 | /// | ||
| 125 | /// safety: for a given TaskPoolRef instance, must always call with the exact | ||
| 126 | /// same generic params. | ||
| 127 | pub unsafe fn get<F: Future, const N: usize>(&'static self) -> &'static TaskPool<F, N> { | ||
| 128 | critical_section::with(|cs| { | ||
| 129 | let ptr = self.ptr.borrow(cs); | ||
| 130 | if ptr.get().is_null() { | ||
| 131 | let pool = ARENA.alloc::<TaskPool<F, N>>(cs); | ||
| 132 | pool.write(TaskPool::new()); | ||
| 133 | ptr.set(pool as *mut _ as _); | ||
| 134 | } | ||
| 135 | |||
| 136 | unsafe { &*(ptr.get() as *const _) } | ||
| 137 | }) | ||
| 138 | } | ||
| 67 | } | 139 | } |
| 68 | } | 140 | } |
