Poll the specified future once on behalf of a guest->host call using an async-lowered import. If it returns `Ready`, return `Ok(None)`. Otherwise, if it returns `Pending`, add it to the set of futures to be polled as part of this instance's event loop until it completes, and then return `Ok(Some(handle))` where `handle` is the waitable handle to return. Whether the future returns `Ready` immedi
(
self,
mut store: StoreContextMut<'_, T>,
future: impl Future<Output = Result<R>> + Send + 'static,
lower: impl FnOnce(StoreContextMut<T>, Option<R>) -> Result<()> + S
| 2993 | /// stack and linear memory. The `lower` function is invoked with `None` if |
| 2994 | /// the future is cancelled. |
| 2995 | pub(crate) fn first_poll<T: 'static, R: Send + 'static>( |
| 2996 | self, |
| 2997 | mut store: StoreContextMut<'_, T>, |
| 2998 | future: impl Future<Output = Result<R>> + Send + 'static, |
| 2999 | lower: impl FnOnce(StoreContextMut<T>, Option<R>) -> Result<()> + Send + 'static, |
| 3000 | ) -> Result<Option<u32>> { |
| 3001 | let token = StoreToken::new(store.as_context_mut()); |
| 3002 | let state = store.0.concurrent_state_mut(); |
| 3003 | let task = state.current_host_thread()?; |
| 3004 | |
| 3005 | // Create an abortable future which hooks calls to poll and manages call |
| 3006 | // context state for the future. |
| 3007 | let (join_handle, future) = JoinHandle::run(future); |
| 3008 | { |
| 3009 | let state = &mut state.get_mut(task)?.state; |
| 3010 | assert!(matches!(state, HostTaskState::CalleeStarted)); |
| 3011 | *state = HostTaskState::CalleeRunning(join_handle); |
| 3012 | } |
| 3013 | |
| 3014 | let mut future = Box::pin(future); |
| 3015 | |
| 3016 | // Finally, poll the future. We can use a dummy `Waker` here because |
| 3017 | // we'll add the future to `ConcurrentState::futures` and poll it |
| 3018 | // automatically from the event loop if it doesn't complete immediately |
| 3019 | // here. |
| 3020 | let poll = tls::set(store.0, || { |
| 3021 | future |
| 3022 | .as_mut() |
| 3023 | .poll(&mut Context::from_waker(&Waker::noop())) |
| 3024 | }); |
| 3025 | |
| 3026 | match poll { |
| 3027 | // It finished immediately; lower the result and delete the task. |
| 3028 | Poll::Ready(result) => { |
| 3029 | let result = result.transpose()?; |
| 3030 | lower(store.as_context_mut(), result)?; |
| 3031 | return Ok(None); |
| 3032 | } |
| 3033 | |
| 3034 | // Future isn't ready yet, so fall through. |
| 3035 | Poll::Pending => {} |
| 3036 | } |
| 3037 | |
| 3038 | // It hasn't finished yet; add the future to |
| 3039 | // `ConcurrentState::futures` so it will be polled by the event |
| 3040 | // loop and allocate a waitable handle to return to the guest. |
| 3041 | |
| 3042 | // Wrap the future in a closure responsible for lowering the result into |
| 3043 | // the guest's stack and memory, as well as notifying any waiters that |
| 3044 | // the task returned. |
| 3045 | let future = Box::pin(async move { |
| 3046 | let result = match future.await { |
| 3047 | Some(result) => Some(result?), |
| 3048 | None => None, |
| 3049 | }; |
| 3050 | let on_complete = move |store: &mut dyn VMStore| { |
| 3051 | // Restore the `current_thread` to be the host so `lower` knows |
| 3052 | // how to manipulate borrows and knows which scope of borrows |
no test coverage detected