aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/raw')
-rw-r--r--embassy-executor/src/raw/mod.rs62
-rw-r--r--embassy-executor/src/raw/trace.rs77
2 files changed, 54 insertions, 85 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 4b17d4982..bdaa32951 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -16,7 +16,7 @@ mod run_queue;
16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] 16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
17mod state; 17mod state;
18 18
19#[cfg(feature = "trace")] 19#[cfg(feature = "_any_trace")]
20pub mod trace; 20pub mod trace;
21pub(crate) mod util; 21pub(crate) mod util;
22#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] 22#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
@@ -41,6 +41,7 @@ use self::state::State;
41use self::util::{SyncUnsafeCell, UninitCell}; 41use self::util::{SyncUnsafeCell, UninitCell};
42pub use self::waker::task_from_waker; 42pub use self::waker::task_from_waker;
43use super::SpawnToken; 43use super::SpawnToken;
44use crate::{Metadata, SpawnError};
44 45
45#[no_mangle] 46#[no_mangle]
46extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem { 47extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem {
@@ -94,11 +95,10 @@ pub(crate) struct TaskHeader {
94 95
95 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. 96 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
96 pub(crate) timer_queue_item: TimerQueueItem, 97 pub(crate) timer_queue_item: TimerQueueItem,
97 #[cfg(feature = "trace")] 98
98 pub(crate) name: Option<&'static str>, 99 pub(crate) metadata: Metadata,
99 #[cfg(feature = "trace")] 100
100 pub(crate) id: u32, 101 #[cfg(feature = "rtos-trace")]
101 #[cfg(feature = "trace")]
102 all_tasks_next: AtomicPtr<TaskHeader>, 102 all_tasks_next: AtomicPtr<TaskHeader>,
103} 103}
104 104
@@ -129,6 +129,10 @@ impl TaskRef {
129 unsafe { self.ptr.as_ref() } 129 unsafe { self.ptr.as_ref() }
130 } 130 }
131 131
132 pub(crate) fn metadata(self) -> &'static Metadata {
133 unsafe { &self.ptr.as_ref().metadata }
134 }
135
132 /// Returns a reference to the executor that the task is currently running on. 136 /// Returns a reference to the executor that the task is currently running on.
133 pub unsafe fn executor(self) -> Option<&'static Executor> { 137 pub unsafe fn executor(self) -> Option<&'static Executor> {
134 let executor = self.header().executor.load(Ordering::Relaxed); 138 let executor = self.header().executor.load(Ordering::Relaxed);
@@ -148,6 +152,12 @@ impl TaskRef {
148 pub(crate) fn as_ptr(self) -> *const TaskHeader { 152 pub(crate) fn as_ptr(self) -> *const TaskHeader {
149 self.ptr.as_ptr() 153 self.ptr.as_ptr()
150 } 154 }
155
156 /// Returns the task ID.
157 /// This can be used in combination with rtos-trace to match task names with IDs
158 pub fn id(&self) -> u32 {
159 self.as_ptr() as u32
160 }
151} 161}
152 162
153/// Raw storage in which a task can be spawned. 163/// Raw storage in which a task can be spawned.
@@ -189,11 +199,8 @@ impl<F: Future + 'static> TaskStorage<F> {
189 poll_fn: SyncUnsafeCell::new(None), 199 poll_fn: SyncUnsafeCell::new(None),
190 200
191 timer_queue_item: TimerQueueItem::new(), 201 timer_queue_item: TimerQueueItem::new(),
192 #[cfg(feature = "trace")] 202 metadata: Metadata::new(),
193 name: None, 203 #[cfg(feature = "rtos-trace")]
194 #[cfg(feature = "trace")]
195 id: 0,
196 #[cfg(feature = "trace")]
197 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()), 204 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
198 }, 205 },
199 future: UninitCell::uninit(), 206 future: UninitCell::uninit(),
@@ -213,11 +220,11 @@ impl<F: Future + 'static> TaskStorage<F> {
213 /// 220 ///
214 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it 221 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it
215 /// on a different executor. 222 /// on a different executor.
216 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 223 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<impl Sized>, SpawnError> {
217 let task = AvailableTask::claim(self); 224 let task = AvailableTask::claim(self);
218 match task { 225 match task {
219 Some(task) => task.initialize(future), 226 Some(task) => Ok(task.initialize(future)),
220 None => SpawnToken::new_failed(), 227 None => Err(SpawnError::Busy),
221 } 228 }
222 } 229 }
223 230
@@ -229,7 +236,7 @@ impl<F: Future + 'static> TaskStorage<F> {
229 let mut cx = Context::from_waker(&waker); 236 let mut cx = Context::from_waker(&waker);
230 match future.poll(&mut cx) { 237 match future.poll(&mut cx) {
231 Poll::Ready(_) => { 238 Poll::Ready(_) => {
232 #[cfg(feature = "trace")] 239 #[cfg(feature = "_any_trace")]
233 let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed); 240 let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed);
234 241
235 // As the future has finished and this function will not be called 242 // As the future has finished and this function will not be called
@@ -244,7 +251,7 @@ impl<F: Future + 'static> TaskStorage<F> {
244 // after we're done with it. 251 // after we're done with it.
245 this.raw.state.despawn(); 252 this.raw.state.despawn();
246 253
247 #[cfg(feature = "trace")] 254 #[cfg(feature = "_any_trace")]
248 trace::task_end(exec_ptr, &p); 255 trace::task_end(exec_ptr, &p);
249 } 256 }
250 Poll::Pending => {} 257 Poll::Pending => {}
@@ -279,6 +286,7 @@ impl<F: Future + 'static> AvailableTask<F> {
279 286
280 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { 287 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
281 unsafe { 288 unsafe {
289 self.task.raw.metadata.reset();
282 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); 290 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
283 self.task.future.write_in_place(future); 291 self.task.future.write_in_place(future);
284 292
@@ -345,10 +353,10 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
345 } 353 }
346 } 354 }
347 355
348 fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> SpawnToken<T> { 356 fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<T>, SpawnError> {
349 match self.pool.iter().find_map(AvailableTask::claim) { 357 match self.pool.iter().find_map(AvailableTask::claim) {
350 Some(task) => task.initialize_impl::<T>(future), 358 Some(task) => Ok(task.initialize_impl::<T>(future)),
351 None => SpawnToken::new_failed(), 359 None => Err(SpawnError::Busy),
352 } 360 }
353 } 361 }
354 362
@@ -359,7 +367,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
359 /// This will loop over the pool and spawn the task in the first storage that 367 /// This will loop over the pool and spawn the task in the first storage that
360 /// is currently free. If none is free, a "poisoned" SpawnToken is returned, 368 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
361 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. 369 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error.
362 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 370 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<impl Sized>, SpawnError> {
363 self.spawn_impl::<F>(future) 371 self.spawn_impl::<F>(future)
364 } 372 }
365 373
@@ -372,7 +380,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
372 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` 380 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn`
373 /// is an `async fn`, NOT a hand-written `Future`. 381 /// is an `async fn`, NOT a hand-written `Future`.
374 #[doc(hidden)] 382 #[doc(hidden)]
375 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> 383 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> Result<SpawnToken<impl Sized>, SpawnError>
376 where 384 where
377 FutFn: FnOnce() -> F, 385 FutFn: FnOnce() -> F,
378 { 386 {
@@ -417,7 +425,7 @@ impl SyncExecutor {
417 /// - `task` must NOT be already enqueued (in this executor or another one). 425 /// - `task` must NOT be already enqueued (in this executor or another one).
418 #[inline(always)] 426 #[inline(always)]
419 unsafe fn enqueue(&self, task: TaskRef, l: state::Token) { 427 unsafe fn enqueue(&self, task: TaskRef, l: state::Token) {
420 #[cfg(feature = "trace")] 428 #[cfg(feature = "_any_trace")]
421 trace::task_ready_begin(self, &task); 429 trace::task_ready_begin(self, &task);
422 430
423 if self.run_queue.enqueue(task, l) { 431 if self.run_queue.enqueue(task, l) {
@@ -430,7 +438,7 @@ impl SyncExecutor {
430 .executor 438 .executor
431 .store((self as *const Self).cast_mut(), Ordering::Relaxed); 439 .store((self as *const Self).cast_mut(), Ordering::Relaxed);
432 440
433 #[cfg(feature = "trace")] 441 #[cfg(feature = "_any_trace")]
434 trace::task_new(self, &task); 442 trace::task_new(self, &task);
435 443
436 state::locked(|l| { 444 state::locked(|l| {
@@ -442,23 +450,23 @@ impl SyncExecutor {
442 /// 450 ///
443 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. 451 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
444 pub(crate) unsafe fn poll(&'static self) { 452 pub(crate) unsafe fn poll(&'static self) {
445 #[cfg(feature = "trace")] 453 #[cfg(feature = "_any_trace")]
446 trace::poll_start(self); 454 trace::poll_start(self);
447 455
448 self.run_queue.dequeue_all(|p| { 456 self.run_queue.dequeue_all(|p| {
449 let task = p.header(); 457 let task = p.header();
450 458
451 #[cfg(feature = "trace")] 459 #[cfg(feature = "_any_trace")]
452 trace::task_exec_begin(self, &p); 460 trace::task_exec_begin(self, &p);
453 461
454 // Run the task 462 // Run the task
455 task.poll_fn.get().unwrap_unchecked()(p); 463 task.poll_fn.get().unwrap_unchecked()(p);
456 464
457 #[cfg(feature = "trace")] 465 #[cfg(feature = "_any_trace")]
458 trace::task_exec_end(self, &p); 466 trace::task_exec_end(self, &p);
459 }); 467 });
460 468
461 #[cfg(feature = "trace")] 469 #[cfg(feature = "_any_trace")]
462 trace::executor_idle(self) 470 trace::executor_idle(self)
463 } 471 }
464} 472}
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index f484abf58..b3086948c 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -95,17 +95,20 @@ use crate::spawner::{SpawnError, SpawnToken, Spawner};
95/// This static provides access to the global task tracker which maintains 95/// This static provides access to the global task tracker which maintains
96/// a list of all tasks in the system. It's automatically updated by the 96/// a list of all tasks in the system. It's automatically updated by the
97/// task lifecycle hooks in the trace module. 97/// task lifecycle hooks in the trace module.
98pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); 98#[cfg(feature = "rtos-trace")]
99pub(crate) static TASK_TRACKER: TaskTracker = TaskTracker::new();
99 100
100/// A thread-safe tracker for all tasks in the system 101/// A thread-safe tracker for all tasks in the system
101/// 102///
102/// This struct uses an intrusive linked list approach to track all tasks 103/// This struct uses an intrusive linked list approach to track all tasks
103/// without additional memory allocations. It maintains a global list of 104/// without additional memory allocations. It maintains a global list of
104/// tasks that can be traversed to find all currently existing tasks. 105/// tasks that can be traversed to find all currently existing tasks.
105pub struct TaskTracker { 106#[cfg(feature = "rtos-trace")]
107pub(crate) struct TaskTracker {
106 head: AtomicPtr<TaskHeader>, 108 head: AtomicPtr<TaskHeader>,
107} 109}
108 110
111#[cfg(feature = "rtos-trace")]
109impl TaskTracker { 112impl TaskTracker {
110 /// Creates a new empty task tracker 113 /// Creates a new empty task tracker
111 /// 114 ///
@@ -125,7 +128,7 @@ impl TaskTracker {
125 /// # Arguments 128 /// # Arguments
126 /// * `task` - The task reference to add to the tracker 129 /// * `task` - The task reference to add to the tracker
127 pub fn add(&self, task: TaskRef) { 130 pub fn add(&self, task: TaskRef) {
128 let task_ptr = task.as_ptr() as *mut TaskHeader; 131 let task_ptr = task.as_ptr();
129 132
130 loop { 133 loop {
131 let current_head = self.head.load(Ordering::Acquire); 134 let current_head = self.head.load(Ordering::Acquire);
@@ -135,7 +138,7 @@ impl TaskTracker {
135 138
136 if self 139 if self
137 .head 140 .head
138 .compare_exchange(current_head, task_ptr, Ordering::Release, Ordering::Relaxed) 141 .compare_exchange(current_head, task_ptr.cast_mut(), Ordering::Release, Ordering::Relaxed)
139 .is_ok() 142 .is_ok()
140 { 143 {
141 break; 144 break;
@@ -165,50 +168,7 @@ impl TaskTracker {
165 } 168 }
166} 169}
167 170
168/// Extension trait for `TaskRef` that provides tracing functionality. 171#[cfg(feature = "trace")]
169///
170/// This trait is only available when the `trace` feature is enabled.
171/// It extends `TaskRef` with methods for accessing and modifying task identifiers
172/// and names, which are useful for debugging, logging, and performance analysis.
173pub trait TaskRefTrace {
174 /// Get the name for a task
175 fn name(&self) -> Option<&'static str>;
176
177 /// Set the name for a task
178 fn set_name(&self, name: Option<&'static str>);
179
180 /// Get the ID for a task
181 fn id(&self) -> u32;
182
183 /// Set the ID for a task
184 fn set_id(&self, id: u32);
185}
186
187impl TaskRefTrace for TaskRef {
188 fn name(&self) -> Option<&'static str> {
189 self.header().name
190 }
191
192 fn set_name(&self, name: Option<&'static str>) {
193 unsafe {
194 let header_ptr = self.ptr.as_ptr() as *mut TaskHeader;
195 (*header_ptr).name = name;
196 }
197 }
198
199 fn id(&self) -> u32 {
200 self.header().id
201 }
202
203 fn set_id(&self, id: u32) {
204 unsafe {
205 let header_ptr = self.ptr.as_ptr() as *mut TaskHeader;
206 (*header_ptr).id = id;
207 }
208 }
209}
210
211#[cfg(not(feature = "rtos-trace"))]
212extern "Rust" { 172extern "Rust" {
213 /// This callback is called when the executor begins polling. This will always 173 /// This callback is called when the executor begins polling. This will always
214 /// be paired with a later call to `_embassy_trace_executor_idle`. 174 /// be paired with a later call to `_embassy_trace_executor_idle`.
@@ -270,7 +230,7 @@ extern "Rust" {
270 230
271#[inline] 231#[inline]
272pub(crate) fn poll_start(executor: &SyncExecutor) { 232pub(crate) fn poll_start(executor: &SyncExecutor) {
273 #[cfg(not(feature = "rtos-trace"))] 233 #[cfg(feature = "trace")]
274 unsafe { 234 unsafe {
275 _embassy_trace_poll_start(executor as *const _ as u32) 235 _embassy_trace_poll_start(executor as *const _ as u32)
276 } 236 }
@@ -278,7 +238,7 @@ pub(crate) fn poll_start(executor: &SyncExecutor) {
278 238
279#[inline] 239#[inline]
280pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { 240pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
281 #[cfg(not(feature = "rtos-trace"))] 241 #[cfg(feature = "trace")]
282 unsafe { 242 unsafe {
283 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) 243 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32)
284 } 244 }
@@ -286,7 +246,7 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
286 #[cfg(feature = "rtos-trace")] 246 #[cfg(feature = "rtos-trace")]
287 { 247 {
288 rtos_trace::trace::task_new(task.as_ptr() as u32); 248 rtos_trace::trace::task_new(task.as_ptr() as u32);
289 let name = task.name().unwrap_or("unnamed task\0"); 249 let name = task.metadata().name().unwrap_or("unnamed task\0");
290 let info = rtos_trace::TaskInfo { 250 let info = rtos_trace::TaskInfo {
291 name, 251 name,
292 priority: 0, 252 priority: 0,
@@ -302,7 +262,7 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
302 262
303#[inline] 263#[inline]
304pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { 264pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
305 #[cfg(not(feature = "rtos-trace"))] 265 #[cfg(feature = "trace")]
306 unsafe { 266 unsafe {
307 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) 267 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32)
308 } 268 }
@@ -310,7 +270,7 @@ pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
310 270
311#[inline] 271#[inline]
312pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { 272pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
313 #[cfg(not(feature = "rtos-trace"))] 273 #[cfg(feature = "trace")]
314 unsafe { 274 unsafe {
315 _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32) 275 _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32)
316 } 276 }
@@ -320,7 +280,7 @@ pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
320 280
321#[inline] 281#[inline]
322pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { 282pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
323 #[cfg(not(feature = "rtos-trace"))] 283 #[cfg(feature = "trace")]
324 unsafe { 284 unsafe {
325 _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32) 285 _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32)
326 } 286 }
@@ -330,7 +290,7 @@ pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
330 290
331#[inline] 291#[inline]
332pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { 292pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
333 #[cfg(not(feature = "rtos-trace"))] 293 #[cfg(feature = "trace")]
334 unsafe { 294 unsafe {
335 _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32) 295 _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32)
336 } 296 }
@@ -340,7 +300,7 @@ pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
340 300
341#[inline] 301#[inline]
342pub(crate) fn executor_idle(executor: &SyncExecutor) { 302pub(crate) fn executor_idle(executor: &SyncExecutor) {
343 #[cfg(not(feature = "rtos-trace"))] 303 #[cfg(feature = "trace")]
344 unsafe { 304 unsafe {
345 _embassy_trace_executor_idle(executor as *const _ as u32) 305 _embassy_trace_executor_idle(executor as *const _ as u32)
346 } 306 }
@@ -356,6 +316,7 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
356/// 316///
357/// # Returns 317/// # Returns
358/// An iterator that yields `TaskRef` items for each task 318/// An iterator that yields `TaskRef` items for each task
319#[cfg(feature = "rtos-trace")]
359fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static { 320fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
360 struct TaskIterator<'a> { 321 struct TaskIterator<'a> {
361 tracker: &'a TaskTracker, 322 tracker: &'a TaskTracker,
@@ -384,6 +345,7 @@ fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
384} 345}
385 346
386/// Perform an action on each active task 347/// Perform an action on each active task
348#[cfg(feature = "rtos-trace")]
387fn with_all_active_tasks<F>(f: F) 349fn with_all_active_tasks<F>(f: F)
388where 350where
389 F: FnMut(TaskRef), 351 F: FnMut(TaskRef),
@@ -395,9 +357,8 @@ where
395impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 357impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor {
396 fn task_list() { 358 fn task_list() {
397 with_all_active_tasks(|task| { 359 with_all_active_tasks(|task| {
398 let name = task.name().unwrap_or("unnamed task\0");
399 let info = rtos_trace::TaskInfo { 360 let info = rtos_trace::TaskInfo {
400 name, 361 name: task.metadata().name().unwrap_or("unnamed task\0"),
401 priority: 0, 362 priority: 0,
402 stack_base: 0, 363 stack_base: 0,
403 stack_size: 0, 364 stack_size: 0,