|
| 1 | +use futures::Future; |
| 2 | +use core::task::Waker; |
| 3 | +use core::task::Poll; |
| 4 | +use core::task::Context; |
| 5 | +use core::task::RawWaker; |
| 6 | +use core::task::RawWakerVTable; |
| 7 | +use core::pin::Pin; |
| 8 | +use core::ptr; |
| 9 | +use crate::syscalls; |
| 10 | + |
| 11 | +/// # Safety |
| 12 | +/// |
| 13 | +/// [[block_on]] yields whenever a future cannot make any progress at present. Yielding is considered unsafe. |
| 14 | +pub unsafe fn block_on<T>(mut future: impl Future<Output = T>) -> T { |
| 15 | + // Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).". |
| 16 | + // IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning. |
| 17 | + let mut pinned_future = Pin::new_unchecked(&mut future); |
| 18 | + |
| 19 | + loop { |
| 20 | + match poll(pinned_future.as_mut()) { |
| 21 | + Poll::Pending => syscalls::raw::yieldk(), |
| 22 | + Poll::Ready(value) => { |
| 23 | + return value; |
| 24 | + } |
| 25 | + } |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> { |
| 30 | + let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; |
| 31 | + let mut context = Context::from_waker(&waker); |
| 32 | + pinned_future.poll(&mut context) |
| 33 | +} |
| 34 | + |
| 35 | +// Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all. |
| 36 | +fn get_dummy_waker() -> RawWaker { |
| 37 | + fn clone(_x: *const ()) -> RawWaker { |
| 38 | + get_dummy_waker() |
| 39 | + } |
| 40 | + |
| 41 | + fn do_nothing(_x: *const ()) {} |
| 42 | + |
| 43 | + // This vtable implements the methods required for managing the lifecycle of the wakers. |
| 44 | + // Our wakers are dummies, so those functions don't do anything. |
| 45 | + static DUMMY_WAKER_VTABLE: RawWakerVTable = |
| 46 | + RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); |
| 47 | + |
| 48 | + // The wakers don't have any implementation, so the instance can simply be null. |
| 49 | + RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) |
| 50 | +} |
0 commit comments