ReviewOS

zig-utils/zig-js

Runtime: serialize async-function resume handoffs

#41
Closed chris opened this 9 days ago ·
9 days ago

Parent: #1

Problem

The sharded no-GIL TSan corpus exposed a data race in api/condition-async-wait.js: one shared-realm thread entered vm.asyncDrive and read Generator.running while another thread completed the prior await drive and wrote running = false. Consecutive already-settled awaits can be drained by different task pumps during this return-tail handoff.

A plain bool provides neither mutual exclusion nor release/acquire publication for the persistent activation state. Holding resume_mutex across the complete async body is not valid because async JS can pump tasks or join while executing and would create reentrancy/lock-order stalls.

Goal

Give each async-function activation a narrow atomic resume-ownership handoff that publishes prior exec/stack/environment state without holding a lock across arbitrary JavaScript execution.

Acceptance criteria

  • Generator running state uses an atomic acquire/release ownership protocol for asyncDrive.
  • The next promise job waits only for the prior drive return tail and never drops a continuation because running is transiently true.
  • Ordinary generator re-entrant resume still throws through the existing resume_mutex policy.
  • A deterministic multi-threaded unit witness proves exact serialized increments and is clean under focused TSan.
  • api/condition-async-wait.js remains semantically green and the full no-GIL TSan corpus shard reports no race.
  • Mutable-state synchronization documentation is updated.
9 days ago

Implemented in 6ef776c. Generator.running is now atomic; asyncDrive acquires resume ownership with CAS and release-stores it after the complete drive, while ordinary generators retain resume_mutex reentrancy behavior. The deterministic 4-thread handoff witness passed in both normal and focused TSan modes, and api/condition-async-wait.js passed 20/20 repeated normal no-GIL runs. The macOS TSan reference case emitted no race but reached only 4/5 completions after 382 seconds, so the Linux production matrix is the authoritative full-case acceptance gate: https://github.com/zig-utils/zig-js/actions/runs/29226671310

9 days ago

Accepted and complete in 6ef776c. Async-function activation resume ownership now uses an atomic release/acquire handoff without holding a lock across arbitrary JS; ordinary generator reentrancy retains its resume_mutex policy. The deterministic handoff witness is normal+TSan green, the previously failing corpus shard passed, and the full replacement gate is 31 success / 1 nightly-only skip / 0 failures: https://github.com/zig-utils/zig-js/actions/runs/29226671310

Sign in to comment on this issue.