aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorTobias Naumann <[email protected]>2025-03-31 16:48:13 +0200
committerTobias Naumann <[email protected]>2025-03-31 16:48:13 +0200
commitc29fc3532b34633b2234c26a7e41e8ba6d628e7f (patch)
tree667bc74b504a65592c805fd3f66197bd2126801f /embassy-executor/src
parent14d079ae84ac28ce860015ad6ca8d040edf3f065 (diff)
parent4d9b41714da77d82811f39bd6feabe161e93552c (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.rs196
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;
50mod spawner; 50mod spawner;
51pub use spawner::*; 51pub use spawner::*;
52 52
53mod 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"))]
62pub mod _export { 57pub 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}