fix-deviant(core): bound app mailbox work per tick

A freeze report from continuous newline-free base64 output exposed an
unbounded mailbox drain: producers can keep refilling the queue and prevent
one app tick from returning to the runtime for input, timers, and drawing.

Process at most 64 messages per tick and wake the runtime if work remains.
Messages retain their order and are not dropped. Document the scheduling
contract and the deliberate deviation from the upstream drain loop.

Add a finite refilling-producer regression that fails with the original
loop and verifies yielding, wakeup rearming, and eventual completion. The
reported full freeze was not consistently reproduced in headless GTK, so
this fixes a demonstrated starvation risk without claiming its root cause.

Test Plan:
- All 119 ghostty-core tests pass with Mesa software OpenGL.
- Release build, Clippy for all core targets with -D warnings, and fmt pass.
- GTK handles Ctrl+C, a follow-up command, and quit after a 15-second flood.

Reference: docs/rewrite/DEVIANT_FIXES.md (entry 40)
This commit is contained in:
ddidderr committed 2026-10-14 23:47:37 +02:00
1 parent 85489a164e
commit 4c31d27888
3 files changed
+80 -2

No files matched your search

+4
View File
@@ -128,6 +128,10 @@ GTK invokes `glib-compile-resources` directly so generated XML/UI files in
thread, plus a pty read thread. Mailboxes are `crossbeam-channel` /
`std::sync::mpsc`; the GTK main thread is woken via `glib` channels.
The `Terminal` is shared behind `Arc<Mutex<..>>` (Ghostty's renderer mutex).
`ghostty-core::App` handles at most 64 mailbox messages per tick and wakes
the runtime again if work remains. Continuous renderer notifications must
yield to GTK input, timers, and drawing instead of extending one tick
indefinitely.
9. **Config:** same file format, same keys, same defaults, same CLI flags,
same docs text (used by `+show-config --docs` and `--help`).
10. **Tests:** every Zig `test "..."` block in a ported file is ported to a