Skip to content

Commit ceec6ed

Browse files
authored
save and restore CallContext for host tasks (#12)
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]>
1 parent 96e83b7 commit ceec6ed

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use {
88
},
99
mpk::{self, ProtectionMask},
1010
AsyncWasmCallState, PreviousAsyncWasmCallState, SendSyncPtr, VMFuncRef,
11-
VMMemoryDefinition, VMStore,
11+
VMMemoryDefinition, VMStore, VMStoreRawPtr,
1212
},
1313
AsContextMut, Engine, StoreContextMut, ValRaw,
1414
},
@@ -1456,6 +1456,51 @@ pub(crate) fn first_poll<T, R: Send + Sync + 'static>(
14561456
.concurrent_state()
14571457
.table
14581458
.push_child(HostTask { caller_instance }, caller)?;
1459+
1460+
// Here we wrap the future in a `future::poll_fn` to ensure that we restore
1461+
// and save the `CallContext` for this task before and after polling it,
1462+
// respectively. This involves unsafe shenanigans in order to smuggle the
1463+
// store pointer into the wrapping future, alas.
1464+
1465+
fn maybe_push<T>(
1466+
store: VMStoreRawPtr,
1467+
call_context: &mut Option<CallContext>,
1468+
task: TableId<HostTask>,
1469+
) {
1470+
let store = unsafe { StoreContextMut::<T>(&mut *store.0.as_ptr().cast()) };
1471+
if let Some(call_context) = call_context.take() {
1472+
log::trace!("push call context for {}", task.rep());
1473+
store.0.component_resource_state().0.push(call_context);
1474+
}
1475+
}
1476+
1477+
fn pop<T>(
1478+
store: VMStoreRawPtr,
1479+
call_context: &mut Option<CallContext>,
1480+
task: TableId<HostTask>,
1481+
) {
1482+
log::trace!("pop call context for {}", task.rep());
1483+
let store = unsafe { StoreContextMut::<T>(&mut *store.0.as_ptr().cast()) };
1484+
*call_context = Some(store.0.component_resource_state().0.pop().unwrap());
1485+
}
1486+
1487+
let future = future::poll_fn({
1488+
let mut future = Box::pin(future);
1489+
let store = VMStoreRawPtr(store.0.traitobj());
1490+
let mut call_context = None;
1491+
move |cx| {
1492+
maybe_push::<T>(store, &mut call_context, task);
1493+
1494+
match future.as_mut().poll(cx) {
1495+
Poll::Ready(output) => Poll::Ready(output),
1496+
Poll::Pending => {
1497+
pop::<T>(store, &mut call_context, task);
1498+
Poll::Pending
1499+
}
1500+
}
1501+
}
1502+
});
1503+
14591504
log::trace!("new child of {}: {}", caller.rep(), task.rep());
14601505
let mut future = Box::pin(future.map(move |result| {
14611506
(

crates/wasmtime/src/runtime/vm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl DerefMut for dyn VMStore + '_ {
238238
/// usage of `Instance` and `ComponentInstance` for example.
239239
#[derive(Copy, Clone)]
240240
#[repr(transparent)]
241-
struct VMStoreRawPtr(NonNull<dyn VMStore>);
241+
pub(crate) struct VMStoreRawPtr(pub(crate) NonNull<dyn VMStore>);
242242

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

0 commit comments

Comments
 (0)