diff options
| author | Grant Miller <[email protected]> | 2023-01-29 12:55:06 -0600 |
|---|---|---|
| committer | Grant Miller <[email protected]> | 2023-01-29 15:52:13 -0600 |
| commit | 48e1aab762e902ee0a132602d3c2f9ec0551cd6b (patch) | |
| tree | 1b504ef8ffcd62dd5071e90158efd28172238648 /embassy-executor/src/raw/mod.rs | |
| parent | 7e251a25509a02f9388a8352522e1a279ad857b1 (diff) | |
executor: Replace `NonNull<TaskHeader>` with `TaskRef`
Diffstat (limited to 'embassy-executor/src/raw/mod.rs')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 63 |
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; | |||
| 43 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; | 43 | pub(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 | /// | 46 | pub(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`]. | ||
| 49 | pub 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 | ||
| 61 | impl TaskHeader { | 58 | impl 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)] | ||
| 76 | pub struct TaskRef { | ||
| 77 | ptr: NonNull<TaskHeader>, | ||
| 78 | } | ||
| 79 | |||
| 80 | impl 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`]. |
| 427 | pub unsafe fn wake_task(task: NonNull<TaskHeader>) { | 454 | pub 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; | |||
| 450 | impl embassy_time::queue::TimerQueue for TimerQueue { | 477 | impl 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 | } |
