aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw/mod.rs
diff options
context:
space:
mode:
authorGrant Miller <[email protected]>2023-01-29 12:55:06 -0600
committerGrant Miller <[email protected]>2023-01-29 15:52:13 -0600
commit48e1aab762e902ee0a132602d3c2f9ec0551cd6b (patch)
tree1b504ef8ffcd62dd5071e90158efd28172238648 /embassy-executor/src/raw/mod.rs
parent7e251a25509a02f9388a8352522e1a279ad857b1 (diff)
executor: Replace `NonNull<TaskHeader>` with `TaskRef`
Diffstat (limited to 'embassy-executor/src/raw/mod.rs')
-rw-r--r--embassy-executor/src/raw/mod.rs63
1 files changed, 45 insertions, 18 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 181dabe8e..10a154a9f 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -43,14 +43,11 @@ pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
43pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; 43pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
44 44
45/// Raw task header for use in task pointers. 45/// Raw task header for use in task pointers.
46/// 46pub(crate) struct TaskHeader {
47/// This is an opaque struct, used for raw pointers to tasks, for use
48/// with funtions like [`wake_task`] and [`task_from_waker`].
49pub struct TaskHeader {
50 pub(crate) state: AtomicU32, 47 pub(crate) state: AtomicU32,
51 pub(crate) run_queue_item: RunQueueItem, 48 pub(crate) run_queue_item: RunQueueItem,
52 pub(crate) executor: Cell<*const Executor>, // Valid if state != 0 49 pub(crate) executor: Cell<*const Executor>, // Valid if state != 0
53 pub(crate) poll_fn: UninitCell<unsafe fn(NonNull<TaskHeader>)>, // Valid if STATE_SPAWNED 50 pub(crate) poll_fn: UninitCell<unsafe fn(TaskRef)>, // Valid if STATE_SPAWNED
54 51
55 #[cfg(feature = "integrated-timers")] 52 #[cfg(feature = "integrated-timers")]
56 pub(crate) expires_at: Cell<Instant>, 53 pub(crate) expires_at: Cell<Instant>,
@@ -59,7 +56,7 @@ pub struct TaskHeader {
59} 56}
60 57
61impl TaskHeader { 58impl TaskHeader {
62 pub(crate) const fn new() -> Self { 59 const fn new() -> Self {
63 Self { 60 Self {
64 state: AtomicU32::new(0), 61 state: AtomicU32::new(0),
65 run_queue_item: RunQueueItem::new(), 62 run_queue_item: RunQueueItem::new(),
@@ -74,6 +71,36 @@ impl TaskHeader {
74 } 71 }
75} 72}
76 73
74/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased.
75#[derive(Clone, Copy)]
76pub struct TaskRef {
77 ptr: NonNull<TaskHeader>,
78}
79
80impl TaskRef {
81 fn new<F: Future + 'static>(task: &'static TaskStorage<F>) -> Self {
82 Self {
83 ptr: NonNull::from(task).cast(),
84 }
85 }
86
87 /// Safety: The pointer must have been obtained with `Task::as_ptr`
88 pub(crate) unsafe fn from_ptr(ptr: *const TaskHeader) -> Self {
89 Self {
90 ptr: NonNull::new_unchecked(ptr as *mut TaskHeader),
91 }
92 }
93
94 pub(crate) fn header(self) -> &'static TaskHeader {
95 unsafe { self.ptr.as_ref() }
96 }
97
98 /// The returned pointer is valid for the entire TaskStorage.
99 pub(crate) fn as_ptr(self) -> *const TaskHeader {
100 self.ptr.as_ptr()
101 }
102}
103
77/// Raw storage in which a task can be spawned. 104/// Raw storage in which a task can be spawned.
78/// 105///
79/// This struct holds the necessary memory to spawn one task whose future is `F`. 106/// This struct holds the necessary memory to spawn one task whose future is `F`.
@@ -135,14 +162,14 @@ impl<F: Future + 'static> TaskStorage<F> {
135 .is_ok() 162 .is_ok()
136 } 163 }
137 164
138 unsafe fn spawn_initialize(&'static self, future: impl FnOnce() -> F) -> NonNull<TaskHeader> { 165 unsafe fn spawn_initialize(&'static self, future: impl FnOnce() -> F) -> TaskRef {
139 // Initialize the task 166 // Initialize the task
140 self.raw.poll_fn.write(Self::poll); 167 self.raw.poll_fn.write(Self::poll);
141 self.future.write(future()); 168 self.future.write(future());
142 NonNull::new_unchecked(self as *const TaskStorage<F> as *const TaskHeader as *mut TaskHeader) 169 TaskRef::new(self)
143 } 170 }
144 171
145 unsafe fn poll(p: NonNull<TaskHeader>) { 172 unsafe fn poll(p: TaskRef) {
146 let this = &*(p.as_ptr() as *const TaskStorage<F>); 173 let this = &*(p.as_ptr() as *const TaskStorage<F>);
147 174
148 let future = Pin::new_unchecked(this.future.as_mut()); 175 let future = Pin::new_unchecked(this.future.as_mut());
@@ -307,7 +334,7 @@ impl Executor {
307 /// - `task` must be set up to run in this executor. 334 /// - `task` must be set up to run in this executor.
308 /// - `task` must NOT be already enqueued (in this executor or another one). 335 /// - `task` must NOT be already enqueued (in this executor or another one).
309 #[inline(always)] 336 #[inline(always)]
310 unsafe fn enqueue(&self, cs: CriticalSection, task: NonNull<TaskHeader>) { 337 unsafe fn enqueue(&self, cs: CriticalSection, task: TaskRef) {
311 #[cfg(feature = "rtos-trace")] 338 #[cfg(feature = "rtos-trace")]
312 trace::task_ready_begin(task.as_ptr() as u32); 339 trace::task_ready_begin(task.as_ptr() as u32);
313 340
@@ -325,8 +352,8 @@ impl Executor {
325 /// It is OK to use `unsafe` to call this from a thread that's not the executor thread. 352 /// It is OK to use `unsafe` to call this from a thread that's not the executor thread.
326 /// In this case, the task's Future must be Send. This is because this is effectively 353 /// In this case, the task's Future must be Send. This is because this is effectively
327 /// sending the task to the executor thread. 354 /// sending the task to the executor thread.
328 pub(super) unsafe fn spawn(&'static self, task: NonNull<TaskHeader>) { 355 pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
329 task.as_ref().executor.set(self); 356 task.header().executor.set(self);
330 357
331 #[cfg(feature = "rtos-trace")] 358 #[cfg(feature = "rtos-trace")]
332 trace::task_new(task.as_ptr() as u32); 359 trace::task_new(task.as_ptr() as u32);
@@ -359,7 +386,7 @@ impl Executor {
359 self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); 386 self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task));
360 387
361 self.run_queue.dequeue_all(|p| { 388 self.run_queue.dequeue_all(|p| {
362 let task = p.as_ref(); 389 let task = p.header();
363 390
364 #[cfg(feature = "integrated-timers")] 391 #[cfg(feature = "integrated-timers")]
365 task.expires_at.set(Instant::MAX); 392 task.expires_at.set(Instant::MAX);
@@ -378,7 +405,7 @@ impl Executor {
378 trace::task_exec_begin(p.as_ptr() as u32); 405 trace::task_exec_begin(p.as_ptr() as u32);
379 406
380 // Run the task 407 // Run the task
381 task.poll_fn.read()(p as _); 408 task.poll_fn.read()(p);
382 409
383 #[cfg(feature = "rtos-trace")] 410 #[cfg(feature = "rtos-trace")]
384 trace::task_exec_end(); 411 trace::task_exec_end();
@@ -424,9 +451,9 @@ impl Executor {
424/// # Safety 451/// # Safety
425/// 452///
426/// `task` must be a valid task pointer obtained from [`task_from_waker`]. 453/// `task` must be a valid task pointer obtained from [`task_from_waker`].
427pub unsafe fn wake_task(task: NonNull<TaskHeader>) { 454pub unsafe fn wake_task(task: TaskRef) {
428 critical_section::with(|cs| { 455 critical_section::with(|cs| {
429 let header = task.as_ref(); 456 let header = task.header();
430 let state = header.state.load(Ordering::Relaxed); 457 let state = header.state.load(Ordering::Relaxed);
431 458
432 // If already scheduled, or if not started, 459 // If already scheduled, or if not started,
@@ -450,7 +477,7 @@ struct TimerQueue;
450impl embassy_time::queue::TimerQueue for TimerQueue { 477impl embassy_time::queue::TimerQueue for TimerQueue {
451 fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { 478 fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) {
452 let task = waker::task_from_waker(waker); 479 let task = waker::task_from_waker(waker);
453 let task = unsafe { task.as_ref() }; 480 let task = task.header();
454 let expires_at = task.expires_at.get(); 481 let expires_at = task.expires_at.get();
455 task.expires_at.set(expires_at.min(at)); 482 task.expires_at.set(expires_at.min(at));
456 } 483 }