ReviewOS

zig-utils/zig-js

CI: establish pending asyncHold registration in lifecycle fixture

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

The full Debug no-GIL corpus gate reports api/thread-lifecycle.js failing with:

Error: continuation cannot run while the lock is held: expected 0 but got 1

This reproduces 10/10 times with a Debug runner built from 80e4595, before the #1103 fixture correction. All recorded threads finish and settle their joins. It is a functional assertion failure, not a sanitizer report or timeout.

The fixture creates the asyncHold worker before main enters lock.hold. Execute a controlled startup-order probe to establish whether the callback acquired the previously free lock before main's hold. Then preserve the intended dead-registrant pending-ticket contract with a registration edge that works under independent no-GIL scheduling.

Acceptance: retain all four async-lifecycle oracles and exact side-effect counts; verify the ticket survives registrant exit, settles after release, and respects async settlement ordering. Serialized/no-GIL Debug, ReleaseSafe and unsuppressed TSan must pass. Keep the upstream reference immutable and audit any owned fixture. No sleeps, exclusions, weaker counts, runtime scheduling changes or increased watchdog.

Related: #1103; queue #933.

9 days ago

Landed in 4025527f.

Main acquires the lock before constructing the asyncHold registrant, then joins the registrant while the hold remains active. This proves the pending ticket survives registrant exit and is granted only after release. The owned fixture retains all four lifecycle oracles and exact side-effect/identity/async-order assertions; upstream reference bytes remain unchanged.

Executed evidence:

  • Original Debug no-GIL case fails 10/10 on pinned 80e4595.
  • A controlled worker-first run records beforeMainHold=1, ran=1 before the original assertion fails: the callback ran before main acquired its hold.
  • Corrected fixture on the same pinned before engine: 25/25 serialized and 25/25 no-GIL passes.
  • Candidate: Debug 25/25 in each mode; ReleaseSafe 50/50 in each mode; unsuppressed TSan 10/10 in each mode. Sanitizer symbols verified, TSAN_OPTIONS unset, no supplied suppressions.
  • Unchanged full ReleaseSafe no-GIL functional gate passes 253/253 with the existing 600-second per-case watchdog.
  • Reference inventory/audit self-tests and all five terminal disposition probes pass. Altered lifecycle reference bytes are rejected with CorpusFixtureDrift before execution. Pinned BunPress checks the existing 51-page output manifest.

No engine source, runtime scheduling, watchdog, case exclusion or assertion weakening is introduced. Flips 0 test262 cases because engine and language-runner behavior are unchanged. The independent Debug timeouts remain in #1105, and #1103 stays open until its full Debug gate acceptance passes.

Sign in to comment on this issue.