aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/lib.rs
diff options
context:
space:
mode:
authorjrmoulton <[email protected]>2025-06-10 15:47:54 -0600
committerjrmoulton <[email protected]>2025-06-10 15:48:36 -0600
commitcfad9798ff99d4de0571a512d156b5fe1ef1d427 (patch)
treefc3bf670f82d139de19466cddad1e909db7f3d2e /embassy-executor/src/lib.rs
parentfc342915e6155dec7bafa3e135da7f37a9a07f5c (diff)
parent6186d111a5c150946ee5b7e9e68d987a38c1a463 (diff)
merge new embassy changes
Diffstat (limited to 'embassy-executor/src/lib.rs')
-rw-r--r--embassy-executor/src/lib.rs211
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}
27check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); 26check_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")]
35mod arch; 44mod 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.
39pub use arch::*; 48pub use arch::*;
49#[cfg(not(feature = "_arch"))]
50pub use embassy_executor_macros::main_unspecified as main;
40 51
41pub mod raw; 52pub mod raw;
42 53
43mod spawner; 54mod spawner;
44pub use spawner::*; 55pub use spawner::*;
45 56
46mod 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"))]
55pub mod _export { 61pub 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}