Skip to content

Commit

Permalink
save and restore CallContext for host tasks (#12)
Browse files Browse the repository at this point in the history
We were already doing this for guest tasks, but I missed doing it for host
tasks, leading to "cannot remove owned resource while borrowed" errors.

Fixes #10.

Signed-off-by: Joel Dice <[email protected]>
  • Loading branch information
dicej authored Feb 14, 2025
1 parent 96e83b7 commit ceec6ed
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
47 changes: 46 additions & 1 deletion crates/wasmtime/src/runtime/component/concurrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
},
mpk::{self, ProtectionMask},
AsyncWasmCallState, PreviousAsyncWasmCallState, SendSyncPtr, VMFuncRef,
VMMemoryDefinition, VMStore,
VMMemoryDefinition, VMStore, VMStoreRawPtr,
},
AsContextMut, Engine, StoreContextMut, ValRaw,
},
Expand Down Expand Up @@ -1456,6 +1456,51 @@ pub(crate) fn first_poll<T, R: Send + Sync + 'static>(
.concurrent_state()
.table
.push_child(HostTask { caller_instance }, caller)?;

// Here we wrap the future in a `future::poll_fn` to ensure that we restore
// and save the `CallContext` for this task before and after polling it,
// respectively. This involves unsafe shenanigans in order to smuggle the
// store pointer into the wrapping future, alas.

fn maybe_push<T>(
store: VMStoreRawPtr,
call_context: &mut Option<CallContext>,
task: TableId<HostTask>,
) {
let store = unsafe { StoreContextMut::<T>(&mut *store.0.as_ptr().cast()) };
if let Some(call_context) = call_context.take() {
log::trace!("push call context for {}", task.rep());
store.0.component_resource_state().0.push(call_context);
}
}

fn pop<T>(
store: VMStoreRawPtr,
call_context: &mut Option<CallContext>,
task: TableId<HostTask>,
) {
log::trace!("pop call context for {}", task.rep());
let store = unsafe { StoreContextMut::<T>(&mut *store.0.as_ptr().cast()) };
*call_context = Some(store.0.component_resource_state().0.pop().unwrap());
}

let future = future::poll_fn({
let mut future = Box::pin(future);
let store = VMStoreRawPtr(store.0.traitobj());
let mut call_context = None;
move |cx| {
maybe_push::<T>(store, &mut call_context, task);

match future.as_mut().poll(cx) {
Poll::Ready(output) => Poll::Ready(output),
Poll::Pending => {
pop::<T>(store, &mut call_context, task);
Poll::Pending
}
}
}
});

log::trace!("new child of {}: {}", caller.rep(), task.rep());
let mut future = Box::pin(future.map(move |result| {
(
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ impl DerefMut for dyn VMStore + '_ {
/// usage of `Instance` and `ComponentInstance` for example.
#[derive(Copy, Clone)]
#[repr(transparent)]
struct VMStoreRawPtr(NonNull<dyn VMStore>);
pub(crate) struct VMStoreRawPtr(pub(crate) NonNull<dyn VMStore>);

// SAFETY: this is the purpose of `VMStoreRawPtr`, see docs above about safe
// usage.
Expand Down

0 comments on commit ceec6ed

Please sign in to comment.