ReviewOS

zig-utils/zig-js

Threads: make join wait for pending asyncJoin settlement

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

Problem

The tsan-threadfuzz-midgc job in main run https://github.com/zig-utils/zig-js/actions/runs/29380249887/job/87242192302 failed deterministically for seed 1:

worker terminate/ThreadLocal asyncHold waiters did not reject after midgc release

publishThreadCompletion() sets ThreadRecord.done = true and wakes synchronous joiners before the finishing thread settles the snapshotted pending_joins. Thread.join() waits only for done, so it can return and drain the joiner queue in that gap. The fuzz oracle can then observe joined threads but not the corresponding asyncJoin().then(... rejection ...) callbacks. TSan makes the publication/settlement window large enough to reproduce.

Scope

  • distinguish result publication from completion of the pre-existing async-join settlement snapshot
  • make Thread.join() wait for both transitions
  • wake joiners after the snapshot is fully settled
  • add a deterministic regression that forces the publication/settlement ordering
  • run focused unit/TSan coverage and rely on the next combined CI run for the expensive full mid-GC fuzz matrix

This is a runtime ordering bug exposed while validating #106, not an infrastructure failure.

9 days ago

Implemented on main as 044a386 (fix(threads): await async join settlement (#107)).

Root cause: publishThreadCompletion() exposed done before settling the snapshotted pre-existing asyncJoin() promises. Thread.join() could therefore return and drain the joiner queue in that publication/settlement gap.

Fix:

  • track whether the pre-existing async-join snapshot has finished settling
  • make synchronous join() wait for both result publication and snapshot settlement
  • broadcast the completion condition after settlement
  • cover the ordering gate deterministically, including early setup-failure transitions

Focused validation:

  • join-filtered unit family: 9/9 passed, 0 leaked
  • same join-filtered family under TSan: 9/9 passed, 0 leaked

The next combined main CI run owns the expensive mid-GC TSan replay.

9 days ago

Completed by 044a386 and verified by the fully green combined main run (32 successful jobs, 0 failures): https://github.com/zig-utils/zig-js/actions/runs/29381215887. The exact previously failing tsan-threadfuzz-midgc job and the non-TSan mid-GC profile both passed.

Sign in to comment on this issue.