| use crate::syscalls; |
| use core::pin::Pin; |
| use core::ptr; |
| use core::task::Context; |
| use core::task::Poll; |
| use core::task::RawWaker; |
| use core::task::RawWakerVTable; |
| use core::task::Waker; |
| use futures::Future; |
| |
| /// # Safety |
| /// |
| /// [[block_on]] yields whenever a future cannot make any progress at present. Yielding is considered unsafe. |
| pub unsafe fn block_on<T>(mut future: impl Future<Output = T>) -> T { |
| // Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).". |
| // IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning. |
| let mut pinned_future = Pin::new_unchecked(&mut future); |
| |
| loop { |
| match poll(pinned_future.as_mut()) { |
| Poll::Pending => syscalls::raw::yieldk(), |
| Poll::Ready(value) => { |
| return value; |
| } |
| } |
| } |
| } |
| |
| fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> { |
| let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; |
| let mut context = Context::from_waker(&waker); |
| pinned_future.poll(&mut context) |
| } |
| |
| // Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all. |
| fn get_dummy_waker() -> RawWaker { |
| fn clone(_x: *const ()) -> RawWaker { |
| get_dummy_waker() |
| } |
| |
| fn do_nothing(_x: *const ()) {} |
| |
| // This vtable implements the methods required for managing the lifecycle of the wakers. |
| // Our wakers are dummies, so those functions don't do anything. |
| static DUMMY_WAKER_VTABLE: RawWakerVTable = |
| RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); |
| |
| // The wakers don't have any implementation, so the instance can simply be null. |
| RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) |
| } |