Skip to content

Add Store.awaitSnapshotCapturable for race-free snapshot coordination#19

Merged
IRus merged 2 commits into
mainfrom
fix/store-await-capturable
Jul 19, 2026
Merged

Add Store.awaitSnapshotCapturable for race-free snapshot coordination#19
IRus merged 2 commits into
mainfrom
fix/store-await-capturable

Conversation

@IRus

@IRus IRus commented Jul 19, 2026

Copy link
Copy Markdown
Member

What

Adds Store.awaitSnapshotCapturable(), a public suspend primitive that returns only once a capturable status (Paused, WaitingForFuel, InHostImport) is published and the execution gate has been released. Documents the publish-before-park ordering on StoreStatus and captureSnapshotState, moves SnapshotSuspensionSafetyJvmTest onto the new primitive, and adds a stress test that captures a parked host import from another thread 32 times.

Why

enterHostImport publishes StoreStatus.InHostImport while the gated execution segment still holds the gate mutex; the mutex is released only when the host continuation actually parks. An embedder that observes status.first { it == InHostImport } on one thread and then calls captureSnapshotState intermittently loses the race against the still-running segment and gets SnapshotStateException("store execution has not parked...") — this is what made hostImportCannotResumeWhileSnapshotTraversalOwnsTheStore flaky. Reordering the publication is not viable because the gate release is implicit in the ContinuationInterceptor machinery, so the fix is an additive awaitable signal: awaitSnapshotCapturable briefly takes the gate mutex, so after it returns a capture cannot fail with "has not parked" unless the guest resumes in between — which it cannot while the host import is still blocked.

Supersedes the test-level dispatcher drain on branch fix/snapshot-suspension-safety-jvm-test.

Testing

  • ./gradlew :core:jvmTest — 107 tests, 0 failures
  • --tests '*SnapshotSuspensionSafety*' rerun 5x, green each time
  • :core:compileKotlinMacosArm64 — commonMain compiles for native

🤖 Generated with Claude Code

IRus and others added 2 commits July 19, 2026 11:53
StoreStatus.InHostImport (and Paused/WaitingForFuel) is published from
inside a gated execution segment, before the executing continuation
parks and StoreExecutionGate releases its mutex. An embedder that
observes status.first { it == InHostImport } on another thread and then
calls captureSnapshotState intermittently hits the fail-fast
tryAcquireCapture and gets "store execution has not parked". This exact
race made SnapshotSuspensionSafetyJvmTest flaky.

Reordering the publication is not an option: the gate release is
implicit in the ContinuationInterceptor machinery and only happens once
the segment actually suspends. Instead, expose a public awaitable
primitive: awaitSnapshotCapturable() suspends until a capturable status
is published AND the gate has been released (by briefly taking the gate
mutex), so a follow-up captureSnapshotState cannot fail with "has not
parked" unless the guest resumes in between - which it cannot while the
parked host import is still blocked.

Also document the publish-before-park ordering on StoreStatus and
captureSnapshotState, switch the previously flaky test to the new
primitive, and add a focused stress test for capture of a parked host
import from another thread. Supersedes the test-level dispatcher drain
on branch fix/snapshot-suspension-safety-jvm-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolve SnapshotSuspensionSafetyJvmTest in favor of the new
Store.awaitSnapshotCapturable API: both the dispatcher drain that main
used in the traversal test and the capture-probe polling loop in the
cross-thread resumption test are superseded by awaiting the execution
gate directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IRus
IRus merged commit f4f4b27 into main Jul 19, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant