diff options
| author | jrmoulton <[email protected]> | 2025-06-10 15:47:54 -0600 |
|---|---|---|
| committer | jrmoulton <[email protected]> | 2025-06-10 15:48:36 -0600 |
| commit | cfad9798ff99d4de0571a512d156b5fe1ef1d427 (patch) | |
| tree | fc3bf670f82d139de19466cddad1e909db7f3d2e /embassy-executor/src/lib.rs | |
| parent | fc342915e6155dec7bafa3e135da7f37a9a07f5c (diff) | |
| parent | 6186d111a5c150946ee5b7e9e68d987a38c1a463 (diff) | |
merge new embassy changes
Diffstat (limited to 'embassy-executor/src/lib.rs')
| -rw-r--r-- | embassy-executor/src/lib.rs | 211 |
1 files changed, 138 insertions, 73 deletions
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 553ed76d3..dfe420bab 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs | |||
| @@ -1,5 +1,4 @@ | |||
| 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(feature = "nightly", feature(waker_getters))] | ||
| 3 | #![allow(clippy::new_without_default)] | 2 | #![allow(clippy::new_without_default)] |
| 4 | #![doc = include_str!("../README.md")] | 3 | #![doc = include_str!("../README.md")] |
| 5 | #![warn(missing_docs)] | 4 | #![warn(missing_docs)] |
| @@ -24,120 +23,186 @@ macro_rules! check_at_most_one { | |||
| 24 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); | 23 | check_at_most_one!(@amo [$($f)*] [$($f)*] []); |
| 25 | }; | 24 | }; |
| 26 | } | 25 | } |
| 27 | check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); | 26 | check_at_most_one!( |
| 27 | "arch-avr", | ||
| 28 | "arch-cortex-m", | ||
| 29 | "arch-cortex-ar", | ||
| 30 | "arch-riscv32", | ||
| 31 | "arch-std", | ||
| 32 | "arch-wasm", | ||
| 33 | "arch-spin", | ||
| 34 | ); | ||
| 28 | 35 | ||
| 29 | #[cfg(feature = "_arch")] | 36 | #[cfg(feature = "_arch")] |
| 30 | #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] | 37 | #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] |
| 31 | #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] | 38 | #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] |
| 39 | #[cfg_attr(feature = "arch-cortex-ar", path = "arch/cortex_ar.rs")] | ||
| 32 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] | 40 | #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] |
| 33 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] | 41 | #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] |
| 34 | #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] | 42 | #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] |
| 43 | #[cfg_attr(feature = "arch-spin", path = "arch/spin.rs")] | ||
| 35 | mod arch; | 44 | mod arch; |
| 36 | 45 | ||
| 37 | #[cfg(feature = "_arch")] | 46 | #[cfg(feature = "_arch")] |
| 38 | #[allow(unused_imports)] // don't warn if the module is empty. | 47 | #[allow(unused_imports)] // don't warn if the module is empty. |
| 39 | pub use arch::*; | 48 | pub use arch::*; |
| 49 | #[cfg(not(feature = "_arch"))] | ||
| 50 | pub use embassy_executor_macros::main_unspecified as main; | ||
| 40 | 51 | ||
| 41 | pub mod raw; | 52 | pub mod raw; |
| 42 | 53 | ||
| 43 | mod spawner; | 54 | mod spawner; |
| 44 | pub use spawner::*; | 55 | pub use spawner::*; |
| 45 | 56 | ||
| 46 | mod config { | ||
| 47 | #![allow(unused)] | ||
| 48 | include!(concat!(env!("OUT_DIR"), "/config.rs")); | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Implementation details for embassy macros. | 57 | /// Implementation details for embassy macros. |
| 52 | /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. | 58 | /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. |
| 53 | #[doc(hidden)] | 59 | #[doc(hidden)] |
| 54 | #[cfg(not(feature = "nightly"))] | 60 | #[cfg(not(feature = "nightly"))] |
| 55 | pub mod _export { | 61 | pub mod _export { |
| 56 | use core::alloc::Layout; | 62 | use core::cell::UnsafeCell; |
| 57 | use core::cell::{Cell, UnsafeCell}; | ||
| 58 | use core::future::Future; | 63 | use core::future::Future; |
| 59 | use core::mem::MaybeUninit; | 64 | use core::mem::MaybeUninit; |
| 60 | use core::ptr::null_mut; | ||
| 61 | |||
| 62 | use critical_section::{CriticalSection, Mutex}; | ||
| 63 | 65 | ||
| 64 | use crate::raw::TaskPool; | 66 | use crate::raw::TaskPool; |
| 65 | 67 | ||
| 66 | struct Arena<const N: usize> { | 68 | pub trait TaskFn<Args>: Copy { |
| 67 | buf: UnsafeCell<MaybeUninit<[u8; N]>>, | 69 | type Fut: Future + 'static; |
| 68 | ptr: Mutex<Cell<*mut u8>>, | ||
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | unsafe impl<const N: usize> Sync for Arena<N> {} | 72 | macro_rules! task_fn_impl { |
| 72 | unsafe impl<const N: usize> Send for Arena<N> {} | 73 | ($($Tn:ident),*) => { |
| 73 | 74 | impl<F, Fut, $($Tn,)*> TaskFn<($($Tn,)*)> for F | |
| 74 | impl<const N: usize> Arena<N> { | 75 | where |
| 75 | const fn new() -> Self { | 76 | F: Copy + FnOnce($($Tn,)*) -> Fut, |
| 76 | Self { | 77 | Fut: Future + 'static, |
| 77 | buf: UnsafeCell::new(MaybeUninit::uninit()), | 78 | { |
| 78 | ptr: Mutex::new(Cell::new(null_mut())), | 79 | type Fut = Fut; |
| 79 | } | 80 | } |
| 80 | } | 81 | }; |
| 81 | 82 | } | |
| 82 | fn alloc<T>(&'static self, cs: CriticalSection) -> &'static mut MaybeUninit<T> { | ||
| 83 | let layout = Layout::new::<T>(); | ||
| 84 | |||
| 85 | let start = self.buf.get().cast::<u8>(); | ||
| 86 | let end = unsafe { start.add(N) }; | ||
| 87 | 83 | ||
| 88 | let mut ptr = self.ptr.borrow(cs).get(); | 84 | task_fn_impl!(); |
| 89 | if ptr.is_null() { | 85 | task_fn_impl!(T0); |
| 90 | ptr = self.buf.get().cast::<u8>(); | 86 | task_fn_impl!(T0, T1); |
| 91 | } | 87 | task_fn_impl!(T0, T1, T2); |
| 88 | task_fn_impl!(T0, T1, T2, T3); | ||
| 89 | task_fn_impl!(T0, T1, T2, T3, T4); | ||
| 90 | task_fn_impl!(T0, T1, T2, T3, T4, T5); | ||
| 91 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6); | ||
| 92 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7); | ||
| 93 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8); | ||
| 94 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); | ||
| 95 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); | ||
| 96 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); | ||
| 97 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); | ||
| 98 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); | ||
| 99 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); | ||
| 100 | task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); | ||
| 101 | |||
| 102 | #[allow(private_bounds)] | ||
| 103 | #[repr(C)] | ||
| 104 | pub struct TaskPoolHolder<const SIZE: usize, const ALIGN: usize> | ||
| 105 | where | ||
| 106 | Align<ALIGN>: Alignment, | ||
| 107 | { | ||
| 108 | data: UnsafeCell<[MaybeUninit<u8>; SIZE]>, | ||
| 109 | align: Align<ALIGN>, | ||
| 110 | } | ||
| 92 | 111 | ||
| 93 | let bytes_left = (end as usize) - (ptr as usize); | 112 | unsafe impl<const SIZE: usize, const ALIGN: usize> Send for TaskPoolHolder<SIZE, ALIGN> where Align<ALIGN>: Alignment {} |
| 94 | let align_offset = (ptr as usize).next_multiple_of(layout.align()) - (ptr as usize); | 113 | unsafe impl<const SIZE: usize, const ALIGN: usize> Sync for TaskPoolHolder<SIZE, ALIGN> where Align<ALIGN>: Alignment {} |
| 95 | 114 | ||
| 96 | if align_offset + layout.size() > bytes_left { | 115 | #[allow(private_bounds)] |
| 97 | panic!("embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/"); | 116 | impl<const SIZE: usize, const ALIGN: usize> TaskPoolHolder<SIZE, ALIGN> |
| 98 | } | 117 | where |
| 118 | Align<ALIGN>: Alignment, | ||
| 119 | { | ||
| 120 | pub const fn get(&self) -> *const u8 { | ||
| 121 | self.data.get().cast() | ||
| 122 | } | ||
| 123 | } | ||
| 99 | 124 | ||
| 100 | let res = unsafe { ptr.add(align_offset) }; | 125 | pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize |
| 101 | let ptr = unsafe { ptr.add(align_offset + layout.size()) }; | 126 | where |
| 127 | F: TaskFn<Args, Fut = Fut>, | ||
| 128 | Fut: Future + 'static, | ||
| 129 | { | ||
| 130 | size_of::<TaskPool<Fut, POOL_SIZE>>() | ||
| 131 | } | ||
| 102 | 132 | ||
| 103 | self.ptr.borrow(cs).set(ptr); | 133 | pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize |
| 134 | where | ||
| 135 | F: TaskFn<Args, Fut = Fut>, | ||
| 136 | Fut: Future + 'static, | ||
| 137 | { | ||
| 138 | align_of::<TaskPool<Fut, POOL_SIZE>>() | ||
| 139 | } | ||
| 104 | 140 | ||
| 105 | unsafe { &mut *(res as *mut MaybeUninit<T>) } | 141 | pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE> |
| 106 | } | 142 | where |
| 143 | F: TaskFn<Args, Fut = Fut>, | ||
| 144 | Fut: Future + 'static, | ||
| 145 | { | ||
| 146 | TaskPool::new() | ||
| 107 | } | 147 | } |
| 108 | 148 | ||
| 109 | static ARENA: Arena<{ crate::config::TASK_ARENA_SIZE }> = Arena::new(); | 149 | #[allow(private_bounds)] |
| 150 | #[repr(transparent)] | ||
| 151 | pub struct Align<const N: usize>([<Self as Alignment>::Archetype; 0]) | ||
| 152 | where | ||
| 153 | Self: Alignment; | ||
| 110 | 154 | ||
| 111 | pub struct TaskPoolRef { | 155 | trait Alignment { |
| 112 | // type-erased `&'static mut TaskPool<F, N>` | 156 | /// A zero-sized type of particular alignment. |
| 113 | // Needed because statics can't have generics. | 157 | type Archetype: Copy + Eq + PartialEq + Send + Sync + Unpin; |
| 114 | ptr: Mutex<Cell<*mut ()>>, | ||
| 115 | } | 158 | } |
| 116 | unsafe impl Sync for TaskPoolRef {} | ||
| 117 | unsafe impl Send for TaskPoolRef {} | ||
| 118 | 159 | ||
| 119 | impl TaskPoolRef { | 160 | macro_rules! aligns { |
| 120 | pub const fn new() -> Self { | 161 | ($($AlignX:ident: $n:literal,)*) => { |
| 121 | Self { | 162 | $( |
| 122 | ptr: Mutex::new(Cell::new(null_mut())), | 163 | #[derive(Copy, Clone, Eq, PartialEq)] |
| 123 | } | 164 | #[repr(align($n))] |
| 124 | } | 165 | struct $AlignX {} |
| 125 | 166 | impl Alignment for Align<$n> { | |
| 126 | /// Get the pool for this ref, allocating it from the arena the first time. | 167 | type Archetype = $AlignX; |
| 127 | /// | ||
| 128 | /// safety: for a given TaskPoolRef instance, must always call with the exact | ||
| 129 | /// same generic params. | ||
| 130 | pub unsafe fn get<F: Future, const N: usize>(&'static self) -> &'static TaskPool<F, N> { | ||
| 131 | critical_section::with(|cs| { | ||
| 132 | let ptr = self.ptr.borrow(cs); | ||
| 133 | if ptr.get().is_null() { | ||
| 134 | let pool = ARENA.alloc::<TaskPool<F, N>>(cs); | ||
| 135 | pool.write(TaskPool::new()); | ||
| 136 | ptr.set(pool as *mut _ as _); | ||
| 137 | } | 168 | } |
| 138 | 169 | )* | |
| 139 | unsafe { &*(ptr.get() as *const _) } | 170 | }; |
| 140 | }) | ||
| 141 | } | ||
| 142 | } | 171 | } |
| 172 | |||
| 173 | aligns!( | ||
| 174 | Align1: 1, | ||
| 175 | Align2: 2, | ||
| 176 | Align4: 4, | ||
| 177 | Align8: 8, | ||
| 178 | Align16: 16, | ||
| 179 | Align32: 32, | ||
| 180 | Align64: 64, | ||
| 181 | Align128: 128, | ||
| 182 | Align256: 256, | ||
| 183 | Align512: 512, | ||
| 184 | Align1024: 1024, | ||
| 185 | Align2048: 2048, | ||
| 186 | Align4096: 4096, | ||
| 187 | Align8192: 8192, | ||
| 188 | Align16384: 16384, | ||
| 189 | ); | ||
| 190 | #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] | ||
| 191 | aligns!( | ||
| 192 | Align32768: 32768, | ||
| 193 | Align65536: 65536, | ||
| 194 | Align131072: 131072, | ||
| 195 | Align262144: 262144, | ||
| 196 | Align524288: 524288, | ||
| 197 | Align1048576: 1048576, | ||
| 198 | Align2097152: 2097152, | ||
| 199 | Align4194304: 4194304, | ||
| 200 | Align8388608: 8388608, | ||
| 201 | Align16777216: 16777216, | ||
| 202 | Align33554432: 33554432, | ||
| 203 | Align67108864: 67108864, | ||
| 204 | Align134217728: 134217728, | ||
| 205 | Align268435456: 268435456, | ||
| 206 | Align536870912: 536870912, | ||
| 207 | ); | ||
| 143 | } | 208 | } |
