ReviewOS

zig-utils/zig-js

Threads: preserve async condition completion through Worker termination and mid-GC cleanup

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

Parents: #482, #502. Related: #478, #727, #791.

Linux scheduled CI on 81ce859 failed the tsan-threadfuzz-midgc gate: https://github.com/zig-utils/zig-js/actions/runs/33102091424/job/98622344507

Command: THREADFUZZ_SEED_TIMEOUT_MS=300000 zig build threadfuzz -Dtsan=true -Dfuzz-midgc=true -Dfuzz-iters=2 (Zig 0.17.0-dev.1818+7051f8e).

Exact failure: seed 2, worker terminate/condition check threw Throw: Error: bad worker terminate/condition cond score 0. Final denominator: 90 programs from seed 1, 1 failure. This is a functional assertion in a sanitizer-enabled run, not a reported ThreadSanitizer data race.

The runWorkerTerminateConditionAsyncCleanupInterleavingKind witness in conformance/threadfuzz.zig registers a Lock.asyncHold -> Condition.asyncWait -> reacquire continuation, confirms readiness, applies mid-GC pressure, notifies under the lock, throws to trigger cleanup, then drains the run loop. The expected condition completion score remains zero. Determine whether the continuation, reacquisition, or cleanup/drain ownership is lost; do not infer the cause from this assertion alone.

Acceptance: reproduce the exact seed and lifecycle; preserve precise live roots and exactly-once notification/reacquire/completion; verify both success and exception cleanup with native job/queue ownership; pass normal and TSan mid-GC gates without added polling delays, weakened assertions, extra unconditional drains, suppression, or disabled GC.

Implementation belongs with the ongoing native stack/queue/job and Worker/Promise lifecycle work. The environment declaration change (#790) does not modify that implementation.

9 days ago

Recurrence on pushed 4f7718d: tsan-threadfuzz-midgc job reports seed 2, worker terminate/condition check threw Throw: Error: bad worker terminate/condition cond score 0. Final denominator: 90 programs from seed 1, 1 failure, 711251ms. The retrieved job log contains no ThreadSanitizer race report; this is the same functional assertion, not sanitizer evidence. Kept separate from the class/error semantic fixes; native job/queue and Worker lifecycle ownership remains with the ongoing lifecycle work.

9 days ago

Recurrence on pushed main 6b964afc: threadfuzz-midgc job 99208644248 failed the same deterministic seed 2 assertion, worker terminate/condition check threw Throw: Error: bad worker terminate/condition cond score 0.

This occurrence is the normal mid-GC profile (THREADFUZZ_SEED_TIMEOUT_MS=300000 zig build threadfuzz -Dfuzz-midgc=true -Dfuzz-iters=20), not TSan. Denominator: 900 programs from seed 1, 1 failure. The paired tsan-threadfuzz-midgc leg passed, as did all unit/TSan/no-GIL corpus gates. This broadens the reproduction evidence beyond the earlier TSan-profile occurrences; the functional lifecycle defect remains exactly the #792 witness.

9 days ago

Fixed on main by d05d274c — fix(threads): preserve in-flight task completion (#792).

The realm now accounts for task ownership from dequeue through completion. Run-loop drains and precise-realm teardown no longer infer quiescence from an empty queue while another interpreter is still delivering a Condition.asyncWait reacquire or asyncHold job. Quiescence observers sleep on a dedicated task-lifecycle condition, with the interpreter published as GC-parked during the native wait; there is no polling delay, unconditional drain, suppression, or disabled collection.

Verification on the committed tree:

  • focused task-queue units: 2/2 passed
  • exact failing mid-GC seed 2: 45 programs, 0 failures
  • full normal mid-GC profile: 900 programs from seed 1, 0 failures (644020 ms)
  • TSan mid-GC profile: 90 programs from seed 1, 0 failures (401262 ms), no TSan report
  • full sharded unit suite: 2,218 passed, 1 skipped, 0 failed, 0 leaked

The deterministic issue witness changed from one failure to zero; no test262 subtree was measured because this is internal shared-realm task lifecycle rather than an ECMAScript semantic case.

Sign in to comment on this issue.