Repository navigation
cmux-tui: terminal host accept loop blocks on events (idle host woke 50x/s) - #16864
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (2)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (3)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughThe runtime changes PTY forced-drain polling and replaces periodic host-listener polling with listener and lifecycle-waker polling. A recovery test measures context switches for parked and adopted template hosts on Linux and macOS. ChangesTerminal host runtime
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant HostShared
participant ActiveClientStream
participant AcceptWaker
participant HostAcceptLoop
HostShared->>AcceptWaker: wake after host exit
ActiveClientStream->>AcceptWaker: wake when active-stream count reaches zero
AcceptWaker-->>HostAcceptLoop: reader descriptor becomes ready
HostAcceptLoop->>AcceptWaker: drain pending bytes
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The idle-host change is ready to merge after normal checks; no actionable risk remains identified. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change is contained within terminal-host waiting and does not establish a new access path or weaken existing authentication. Remaining uncertainty concerns cleanup reliability under exceptional notification failures. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 24 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (24 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…hile parked or adopted A Freestyle VM baked from main (cmux-tui 37ee6af) measured the warm template terminal host (__terminal-host --bootstrap-stdio, started at bake, adopted by the clone's daemon) at about 50 wakeups per second: its accept loop called accept4 (EAGAIN) and poll(listener, 20 ms) for the life of the terminal (strace: 488 polls and 489 accept4 in 10 s). The next commit brings feat-cmux-next's fix (51b6863) to main. This test fails now: 498 context switches parked and 498 adopted in 10 s each (hosted run 37009612379). The existing idle test covers hosts the daemon launches; this one covers the bake path: park a template host (fenced shutdown, state wiped), count its context switches over 10 s, adopt it with a fresh-identity daemon, and count again. Each window allows 5 switches (a 1 Hz wake gives at least 10). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… polling Root cause (see the previous commit): the host's accept loop polled its listener with a 20 ms timeout only to re-check `dead` and the launch-owner deadline, for the whole life of every terminal, so an idle host woke about 50 times a second (a Freestyle VM baked from main: 488 polls in 10 s). The loop now polls the listener plus an accept waker, a nonblocking socket pair that terminal exit and the last client stream's close write to; the launch-owner deadline is a one-shot timeout used only until it passes. The forced PTY drain also stops polling a hung-up drain waiter, which stayed readable and busy-looped the rest of the drain window. This is the terminal-host part of feat-cmux-next's 51b6863 (cherry-picked from that commit's terminal_host_runtime.rs only; the rest of that commit depends on code main does not have), so the VM image stops waking. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3bbf430 to
8fc5e56
Compare
|
Merge receipt for |
67001f1 Update Cloud sidebar tests for the redesign and deferred workspace selection (manaflow-ai#16882) 9a332ec cmux-tui: terminal host accept loop blocks on events (idle host woke 50x/s) (manaflow-ai#16864) 7ba85b7 Merge pull request manaflow-ai#16781 from manaflow-ai/cloud-sidebar-followups d6a22e7 Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 a3e78a6 refresh hidden cloud detail pools 6cac783 Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 396571d Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 6e324f4 Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 b053083 remove obsolete fleet freshness argument 9f49df6 Merge remote-tracking branch 'origin/cloud-sidebar-followups' into repair-pr16781 08c1463 remove duplicate fork monitor helper 77181d7 fix: remove duplicate fork monitor argument builder ee62151 use shared fork monitor contract in CLI bbccaec Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 8cd5139 merge cloud row cleanup 4765a31 Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 d649d29 restore cloud sidebar locale translations 1452e4c Merge remote-tracking branch 'origin/cloud-sidebar-followups' into repair-pr16781 45c2cbd Merge remote-tracking branch 'origin/cloud-new-machine-top' into repair-pr16781 dd52822 fix(localization): avoid stacked merge duplicate locales 09ed71b fix tab density enum conformance f6595f5 merge cloud machine creation gate dc7dd14 merge cloud sidebar base and preserve follow-ups 1b83129 fix(ci): restore shared Codex fork monitor helper a713a66 review fixes: a wide tab floor narrows the other mode bar tabs instead of overflowing, new strings in all 20 locales 969516b refresh cloud machines back to the bottom right of the panel 04331c1 right sidebar min (and opening) width 295, just enough for the machine tabs with counts c4240cf cloud sidebar follow-ups: displays tab, new workspace on top, refresh row above my devices, tabs never clip
…eups) (#17015) * cmux-tui: failing test, an idle daemon wakes up periodically Starts a headless daemon with one terminal running cat, keeps an event subscription and a terminal attach open, and counts context switches and CPU of the daemon and the terminal host over a quiet 10 s window. The terminal host part is fixed on main (#16864); the daemon still polls (on a Cloud VM: main thread 241, journal 121, session journal 61 switches per minute). (cherry picked from commit dc5cb26 on feat-cmux-next) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: the daemon blocks on events instead of polling (no idle wakeups) Port of the daemon part of 51b6863 from feat-cmux-next to main. The terminal host accept loop part is already on main (#16864). Root cause: daemon loops waited with a fixed timeout only to re-check a flag, or retried a persistent error at once. On a Cloud VM an idle daemon's main thread made 241, its journal thread 121 and its session journal thread 61 voluntary context switches per minute. Polls removed (each now waits for the event that can change the result): headless main loop (250 ms recv_timeout; now a condvar woken by signals, shutdown requests and the remote runtime's end), stream threads (100 ms recv_timeout; now a StreamInterrupt fired by writer close, stream close and attach cancel), session event and journal streams (1 s epoch waits), journal fanout tailer, journal hook dispatcher, journal plugin supervisor (condvar plus a waitid(WNOWAIT) exit thread), idle-close reaper (sleeps until the next policy deadline), remote runtime bootstrap and browser proxy parent waits. Spins removed: accept loops retried EMFILE/ENFILE/ENOBUFS at once (shared capped jittered Backoff), Kitty budget worker re-ran an identical wave, local PTY reader slept 1 ms on WouldBlock. Not ported: the terminal reaper deadline deferral and the connection scheduler cancel type (their files do not exist on main). (cherry picked from commit 51b6863 on feat-cmux-next, conflicts resolved) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: review fixes for the daemon wakeup port - Session event and session journal streams also stop when their outbound closes alone (a victim of a full connection queue); before, the fired interrupt made the wait return at once and the loop spun until the next journal event. - Idle-close reaper re-evaluates at once after any due terminal (a failed close included), so a failed close is retried after one more period; it used to wait for a policy change or a detach. - AttachTap::try_send drops its queue lock before cancel(), whose interrupt wakers lock the same queue. - The parent-exit watch runs on a detached thread instead of spawn_blocking, so dropping the runtime on shutdown no longer waits for the parent to exit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: drop a needless path qualification (clippy) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * cmux-tui: rustfmt Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An idle terminal host woke about 50 times a second. The VM image lead measured it on a Freestyle VM baked from main (
37ee6af9846): strace showed 488poll(listener, 20 ms)timeouts and 489accept4= EAGAIN in 10 s on the warm template host's main thread.Root cause: the host's accept loop polled its listener with a 20 ms timeout only to re-check
deadand the launch-owner deadline, for the life of every terminal.Fix (the terminal-host part of feat-cmux-next's 51b6863): the loop polls the listener plus an accept waker (a nonblocking socket pair that terminal exit and the last client stream's close write to). The launch-owner deadline is a one-shot timeout used only until it passes. The forced PTY drain also stops polling a hung-up drain waiter.
Test first (red then green):
idle_template::parked_and_adopted_template_hosts_do_not_wake_while_idleparks a warm template host the way the bake does, counts its context switches over 10 s, then adopts it with a fresh-identity daemon and counts again. Each window allows 5 switches.Depends on #16862 (main currently fails
cargo fmt, which stops the hosted cmux-tui test jobs).Changelog
Fixed: an idle terminal no longer wakes its terminal host process 50 times a second.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Stops an idle terminal from waking its terminal host process about 50 times a second by making the host's accept loop block on events instead of polling.
deadand the launch-owner deadline; it now blocks on the listener plus an accept waker.Written for commit 8fc5e56. Summary will update on new commits.
Summary by CodeRabbit