diff --git a/wasm-core/jvmTest/wasm/core/SnapshotSuspensionSafetyJvmTest.kt b/wasm-core/jvmTest/wasm/core/SnapshotSuspensionSafetyJvmTest.kt index 1e356cf..a055797 100644 --- a/wasm-core/jvmTest/wasm/core/SnapshotSuspensionSafetyJvmTest.kt +++ b/wasm-core/jvmTest/wasm/core/SnapshotSuspensionSafetyJvmTest.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.async +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -56,6 +57,16 @@ class SnapshotSuspensionSafetyJvmTest { instance.invoke("resume") } store.status.first { it == StoreStatus.InHostImport } + // InHostImport is published before the import's continuation + // parks. A capture probe only succeeds once the running segment + // has suspended and released the execution gate, so poll it to + // guarantee the completion below resumes a parked continuation + // on the resumer thread instead of finishing the await inline. + withTimeout(5_000) { + while (runCatching { store.captureSnapshotState(instance) }.isFailure) { + delay(1) + } + } assertFalse(invocation.isCompleted) withContext(resumerDispatcher) { @@ -112,6 +123,10 @@ class SnapshotSuspensionSafetyJvmTest { try { val invocation = async(invocationDispatcher) { instance.invoke("wait") } store.status.first { it == StoreStatus.InHostImport } + // InHostImport is published before host code runs. Drain the + // single-thread dispatcher to prove that the host continuation + // has actually suspended and released the store execution gate. + withContext(invocationDispatcher) { Unit } val captureStarted = CountDownLatch(1) val finishCapture = CountDownLatch(1)