Repository navigation
adopt CM#705 sync-call scheduling: exclusive-thread resumability, candidate sets, backpressure STARTING #249
Description
CM#705 (merged upstream; migration map polyengine#173) changed the sync-call mini-scheduler's semantics beyond the may_enter removal: the exclusive thread is no longer excluded from the resume candidate set, and callback-task threads parked on the exclusive lock become resumable during a sync call. polyengine's driveSyncLift (runtime/src/task/scheduler.ts) implements the pinned (pre-#705) form — candidates exclude inst.exclusiveThread — and the adjacent backpressure behavior produces pre-#705 subtask codes.
New/changed corpus rows pinning the merged semantics (xfailed under class cm705-sync-sched until this issue closes):
test/async/during-sync-call-exclusive-resume.wast(new; replaces the deletedduring-sync-call-no-exclusive-resume.wastwith inverted semantics): a parked callback-task thread holding/waiting on the exclusive lock must be resumable mid-sync-call.test/async/during-sync-scheduling-candidates.wast(new, 484 lines): candidate-set membership per thread kind; §3 (parked callback-task threads, incl. driven from a sibling), §4 (callback thread blocked mid-frame holding the lock), §5 (sync-lifted async-typed function's thread blocked mid-frame) expect resumability the current scheduler refuses.test/async/during-sync-call-may-block-if-other-ready-threads.wast(rewritten): appended third component needs mid-sync-call resumption of a parked callback-task thread.test/async/during-sync-call-no-sibling-resume.wast: the pinned rule (only same-instance threads) is unchanged, but the expected trap is now "cannot block a synchronous task before returning" where we produce the deadlock message — verify/align the trap site.test/async/sync-streams.wast(changed by the #705 commit): an async-lowered call into a callee whose exclusive lock is held now returns STARTING (queued by automatic backpressure) instead of STARTED, and the rendezvous completion codes swap (COMPLETED|4 / DROPPED|4). Requires the queuing behavior, not just the candidate set.
Scope of the fix:
- Drop the
t !== task.inst.exclusiveThreadexclusion indriveSyncLift; align the candidate set with mergedcanon_lift(all ready threads of the callee instance). - Adopt the surrounding merged semantics the new rows exercise: exclusive-lock interaction with the mini-scheduler, backpressure queuing of async-lowered entries while the lock is held (STARTING), and the trap-message alignment in the no-sibling case.
- Retire the
cm705-sync-schedxfail class; the stale-xfail detector enforces completeness.
Authority: design/mvp/canonical-abi/definitions.py at the advanced pin (tie-breaker), Concurrency.md §Reentrance/§Blocking as merged in CM#705. Scheduler core is single-owner territory (AGENTS.md): coder-hard at most, close orchestrator review.
Activity
lannbot commentedon Aug 30, 2026
Scope re-derivation before implementation, two findings:
1. CM#716 overlap (open upstream, see #250). #716 restructures the callback event-loop turn (
wait_from_callback, the YIELD/WAIT exclusive-lock dance) but does NOT touch this issue's core: thecanon_liftsync drive loop's candidate set (the exclusive-thread exclusion removal) andcanon_lower's backpressure/initial-status behavior are #705 semantics already at our pin, byte-identical in #716. Safe to implement now:driveSyncLift's exclusion removal, theduring-sync-call-no-sibling-resumetrap-message alignment ("cannot block a synchronous task before returning"). The callback-loop candidate rows (§3/§4/§6 ofduring-sync-scheduling-candidates) are #152-translate-blocked in the corpus anyway AND sit in #716's blast radius — implement them last, or after #716 settles.2. The
sync-streams.wast:208row collides with the #43 adjudication. The row's new STARTING expectation is the pristine-definitions.py answer that #43 adjudicated as an upstream test defect when the expectation pointed the other way (STARTED, satisfied via the hold-gate + drain-to-quiescence entry policy mirroring wasmtime's deferred-entry model). CM#705 flipping the committed expectation is upstream declaring the pristine answer normative under the post-may_enter model — so adopting this row means revisiting #43's named adjudication, not just tweaking codes: the drain-to-quiescence entry policy itself is what answers STARTED. Check what wasmtime's deferred-entry policy looks like post-#705-adoption before choosing (the parity policy allows either conforming policy only if the corpus row is schedule-independent — and upstream has now made it the committed expectation, which was exactly the #43 exit condition's shape).Sequencing consequence: this track is one PR with two reviewed decisions (exclusion removal — mechanical; entry-policy revision — adjudication-grade), not a mechanical sweep. The xfail class holds until then.
lannbot commentedon Sep 5, 2026
Triage 2026-09-05: adding spec-divergence (it is a named xfail class against the pinned reference) and policy (finding 2 above is an adjudication revisit of #43's entry policy, a deltic-owned decision). p2 unchanged.
Two updates to the scope re-derivation above:
8892da0lands — sequence this track after that advance so the callback-turn shape is implemented once, against the mergedwait_from_callback.async/sync-streams.json:208carriescm705-sync-schedin harness/src/xfail.ts today. Theduring-sync-scheduling-candidates/during-sync-call-exclusive-resume/during-sync-call-may-block-if-other-ready-threadsrows this issue lists are classed under deferred threads (memory64 + shared-everything threads: deferred feature tracking #12) — they die at instantiation on 🧵 thread built-ins before reaching the scheduler — and Pin-blocked conformance residues (#13 exit): name-option + thread-encoding xfails need wasmparser >= 0.255 #152 (the "translate-blocked" note above) is closed since the wasm-tools 0.258 bump. So the corpus evidence for the candidate-set change (scope item 1) is masked by memory64 + shared-everything threads: deferred feature tracking #12 until those rows can instantiate; the exclusion removal indriveSyncLiftshould carry its own runtime unit pins rather than lean on the corpus.Net: the PR shape stands as described — exclusion removal (mechanical, unit-pinned) plus the entry-policy revision (adjudication-grade, owns the single live xfail).
lannbot commentedon Sep 12, 2026
Triage: p2 → p1 for the remaining executable conformance failure, after the consumer-facing hangs/leaks/valid-operation failures. Scope correction: #307 already removed the exclusive-thread candidate exclusion and added drive_sync_lift_candidates_test.ts; do not redo scope item 1. Current main still carries the single cm705-sync-sched xfail in async/sync-streams.json: the guest assertion traps on initial/completion status codes. Remaining work is the backpressure/entry-policy decision and implementation needed to retire that row. The #43 adjudication must be revisited explicitly; promotion is not a ruling that its replacement policy is already decided.