| 1 | use core::task::{RawWaker, RawWakerVTable, Waker}; |
| 2 | |
| 3 | use super::{wake_task, TaskHeader, TaskRef}; |
| 4 | |
| 5 | static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop); |
| 6 | |
| 7 | unsafe fn clone(p: *const ()) -> RawWaker { |
| 8 | RawWaker::new(data:p, &VTABLE) |
| 9 | } |
| 10 | |
| 11 | unsafe fn wake(p: *const ()) { |
| 12 | wake_task(TaskRef::from_ptr(p as *const TaskHeader)) |
| 13 | } |
| 14 | |
| 15 | unsafe fn drop(_: *const ()) { |
| 16 | // nop |
| 17 | } |
| 18 | |
| 19 | pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { |
| 20 | Waker::from_raw(waker:RawWaker::new(data:p.as_ptr() as _, &VTABLE)) |
| 21 | } |
| 22 | |
| 23 | /// Get a task pointer from a waker. |
| 24 | /// |
| 25 | /// This can be used as an optimization in wait queues to store task pointers |
| 26 | /// (1 word) instead of full Wakers (2 words). This saves a bit of RAM and helps |
| 27 | /// avoid dynamic dispatch. |
| 28 | /// |
| 29 | /// You can use the returned task pointer to wake the task with [`wake_task`](super::wake_task). |
| 30 | /// |
| 31 | /// # Panics |
| 32 | /// |
| 33 | /// Panics if the waker is not created by the Embassy executor. |
| 34 | pub fn task_from_waker(waker: &Waker) -> TaskRef { |
| 35 | // make sure to compare vtable addresses. Doing `==` on the references |
| 36 | // will compare the contents, which is slower. |
| 37 | if waker.vtable() as *const _ != &VTABLE as *const _ { |
| 38 | panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor." ) |
| 39 | } |
| 40 | // safety: our wakers are always created with `TaskRef::as_ptr` |
| 41 | unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) } |
| 42 | } |
| 43 | |