Skip to content

fix(io): release abandoned JS channel waiters when their run ends - #1976

Merged
Lorenzobattistela merged 4 commits into
bendlang:mainfrom
EpsilonPhoenix:fix/js-channel-abandoned-waiters
Oct 31, 2026
Merged

Lorenzobattistela merged 4 commits into
bendlang:mainfrom
EpsilonPhoenix:fix/js-channel-abandoned-waiters

Conversation

@EpsilonPhoenix

Copy link
Copy Markdown
Contributor

A nested JavaScript IO run can exit or throw while a channel sender is parked behind a live waiter. Its abandoned queue entry keeps the payload and continuation reachable until it reaches the head, allowing repeated nested runs to retain them indefinitely.

Register parked channel waiters with their owning run and release them when that run ends. Waking or timing out a waiter removes its cleanup registration. Queue compaction keeps abandoned entries bounded behind a waiter that stays live.

Validation on Linux:

  • New blocking/timed sender regression covers nested exit and throw paths: piled up: 999 on main, bounded with the fix. Passes interpreted and as emitted JS, independently rerun by the parent agent.
  • Five related channel/timeout fixtures pass across interpreter, emitted JS and native C; re-entry and timer regressions also pass.
  • Repository gate: 54/54; git diff --check passes.
  • GPT-6.1-Terra medium review-agent review: no findings.

The new regression is JS-only because it exercises nested host IO and inspects queue retention. The mini-cluster gate could not start because the cluster hostname did not resolve; GPU lanes were not run.

EpsilonPhoenix and others added 2 commits October 30, 2026 18:40
A waiter whose nested IO returned is not counted dead, so chan_park sheds
once the queue passes twice what the last shed kept + 64: behind a live
waiter they stay O(live) at O(1) a park. io_run (comp.ts) is untouched,
which keeps comp.ts under its 66k ttok cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Lorenzobattistela Lorenzobattistela self-assigned this Oct 31, 2026
Lorenzobattistela and others added 2 commits October 31, 2026 18:07
chan_shed's keep was only reset by a shed, so after many live waiters were
parked and woken, abandoned ones piled up to twice the old peak. A wake
now lowers it. chan_dead names the never-wakes test chan_head and
chan_shed share, and the shed compacts in place in one pass. The test
drains 300 live senders first and checks the longest the queue gets
(455 before, 601 on main).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Abandoned waiters stay under twice the waiters live at the last shed + 64,
not the live now, and go only at a later park on the row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Lorenzobattistela Lorenzobattistela left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this down. The cleanup set in io_run took comp.ts from
65,998 to 66,016 ttok, over its 66k cap, so we reworked the fix inside
bend2/effs/chan.js and pushed it here (af585e4, b1fd47f, ea72740):

  • comp.ts is back to main's: io_run has no cleanups.
  • chan_shed drops every waiter that will never wake (chan_dead: gone, or its
    IO has returned) in one in-place pass; chan_late's shed uses it too.
  • chan_park sheds once the queue passes twice row.keep + 64, at O(1)
    amortized; a wake lowers keep, so draining live waiters does not leave a
    stale high threshold.
  • The test first parks and drains 300 live senders, then checks the longest
    the queue gets behind a live one: 601 on main, bounded with the fix.

This is a hotfix, and its bound is weaker than an eager release: abandoned
waiters stay under twice the waiters live at the last shed + 64, and go only
at a later park on the same channel. Releasing them when io_run returns is
the better fix, once comp.ts has room under its cap.

Gates on main 6a986eb: repo 54/54, test 1800/1800, perf 124/124,
ping 81/81, safe 0 false reject.

@Lorenzobattistela
Lorenzobattistela merged commit ecb5bd4 into bendlang:main Oct 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants