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 | |