ReviewOS

zig-utils/zig-js

CI: investigate no-GIL Condition notification count failure

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

The ReleaseSafe no-GIL functional gate failed on sync/condition-notify-all.js at 80e4595.

Hosted execution passed 62/63 shard cases. The failing case completed in 7 ms and reported:

Error: notify woke the parked waiter (lap 0): expected 1 but got 0

All three recorded threads were done, exited, and had settled joins. This was a functional assertion failure, not a sanitizer abort or timeout.

Investigate waiter registration and the fixture's startup ordering under independently scheduled no-GIL workers. Establish whether this is an engine wake-count defect or an assertion made before a waiter has necessarily parked; the CI output alone does not distinguish them.

Acceptance:

  • Reproduce with the original case and pinned engine before changing either implementation or fixture.
  • Preserve exact notification counts for a demonstrably registered waiter and the subsequent empty queue.
  • Verify serialized, no-GIL Debug/ReleaseSafe, and unsuppressed TSan controls, plus the unchanged functional gate.
  • Do not exclude the case, loosen its assertions, add timing sleeps, or increase the gate budget.

Queue: #933.

9 days ago

Reproduced with a ReleaseSafe binary built from 80e4595: the unmodified case failed 2/100 no-GIL runs and passed 100/100 serialized runs. Both failures were the same expected 1 but got 0 wake-count assertion seen in CI. Binary SHA-256: 35b3ac18b7e78622aff82135689d6ee1f38ff240ca96cccfbcd78ec5095195c2.

A forced worker-first execution reports waitCalls=0, ready=1, woken=0 before the original assertion fails. The notifier can finish before main acquires the lock; main then skips the predicate loop entirely. There was no waiter to wake, so zero is the correct engine result.

Holding the lock before constructing the notifier establishes the required edge: Condition.wait registers its ticket before releasing that lock, and the notifier must acquire the lock before it publishes readiness or notifies. The corrected fixture retains all original empty-queue, single-waiter, repeated-notify and per-condition assertions. It passed 100/100 runs in each mode on the same pinned before engine, without any runtime change.

The candidate uses an explicitly inventoried owned fixture and keeps the vendored reference bytes unchanged. The source-drift guard and inventory audit check both source identities. The unchanged full ReleaseSafe no-GIL gate now passes 253/253; Debug corpus and unsuppressed TSan qualification are still running.

9 days ago

The condition registration correction is landed in fea2e175.

The notifier is constructed while main holds the lock, so its acquisition follows Condition.wait's ticket registration and lock release. All original notification-count assertions remain exact. The owned fixture is checksum-inventoried; the upstream reference remains byte-for-byte unchanged. A deliberate upstream-source change is rejected with CorpusFixtureDrift before execution, and audit self-tests reject missing fixture metadata and incorrect fixture hashes.

Verified:

  • Corrected fixture on pinned 80e4595: 100/100 passes in each mode, versus 2/100 no-GIL failures for the original.
  • Candidate ReleaseSafe: 100/100 in each mode; Debug: 25/25 in each mode; unsuppressed TSan: 10/10 in each mode. Sanitizer symbols checked, TSAN_OPTIONS unset, no supplied suppressions.
  • Full ReleaseSafe no-GIL gate: 253/253, unchanged 600-second per-case watchdog.
  • Serialized Debug corpus: all 246 unique listed cases pass. The same case set completed with isolation after cumulative retention took the unsharded process past the existing memory cap; the interrupted run is not claimed as a complete pass.
  • Reference inventory/audit self-tests, all five terminal disposition probes, and pinned 51-page docs manifest check pass. Engine sources are unchanged; flips 0 test262 cases.

The full Debug no-GIL gate is not green: 250/253 pass. Its lifecycle assertion also fails 10/10 on the pinned parent and is tracked in #1104. The unchanged watchdog reports timeouts for the validation-storm and futex cases, tracked in #1105. #1103 remains open for its full-gate acceptance requirement; no baseline result or watchdog was relaxed to hide those failures.

9 days ago

The remaining full Debug no-GIL gate now passes 253/253 under the unchanged 600-second per-case watchdog; full ReleaseSafe also passes 253/253. This completes the outstanding acceptance check after the registered-waiter correction in fea2e17, the separately tracked lifecycle registration correction in 4025527, and #1105's futex correction in 729837d plus block-layout fix in 969c0f5c.

The original notification/empty-queue oracles and all corpus cases remain checked. Debug, ReleaseSafe, and unsuppressed instrumented TSan controls in serialized and no-GIL modes passed as documented above. Final default/verify/mid-GC/TSan fuzz checks also pass. Full combined CI integration checks for the new push are pending; the earlier cancelled CI run is not a full-suite pass.

Sign in to comment on this issue.