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