Source Code Analysis
Direct analysis of flow control mechanisms in 6 major terminals.Executive Summary
Copy
+-----------------------------------------------------------------------+
| FLOW CONTROL COMPARISON |
+-----------------------------------------------------------------------+
| |
| Terminal Flow Control Type Render ACK Evidence |
| ---------- ------------------ ---------- ------------- |
| Alacritty None X FairMutex |
| Ghostty BlockingQueue(64) X No feedback |
| xterm.js 50MB watermark X Callback at parse|
| Kitty POLLIN control X Best native |
| WezTerm Time-based poll X Coalesce only |
| Hyper None (xterm.js) X Inherits limits |
| MonoTerm ACK Gate O pull() method |
| |
+-----------------------------------------------------------------------+
Alacritty Analysis
Copy
+-----------------------------------------------------------------------+
| ALACRITTY: FairMutex Pattern |
+-----------------------------------------------------------------------+
| |
| What FairMutex does: |
| |
| Ensures fair lock acquisition order between threads |
| Prevents starvation during high contention |
| |
| What FairMutex does NOT do: |
| |
| X Provide backpressure from renderer to PTY |
| X Signal render completion |
| X Gate data emission |
| |
| PTY Event Loop: |
| |
| PTY readable --> process bytes --> send Wakeup event |
| | |
| v |
| Fire-and-forget! |
| No wait for render |
| |
+-----------------------------------------------------------------------+
Ghostty Analysis
Copy
+-----------------------------------------------------------------------+
| GHOSTTY: Fixed Capacity Queue |
+-----------------------------------------------------------------------+
| |
| Architecture: |
| |
| BlockingQueue with 64 message capacity |
| Draw interval targets ~120 FPS |
| |
| Behavior: |
| |
| When queue full: Producer blocks |
| When queue empty: Consumer waits |
| |
| Limitation: |
| |
| This is buffer-based, NOT render-synchronized |
| Queue depth != render completion |
| |
+-----------------------------------------------------------------------+
xterm.js Analysis
Copy
+-----------------------------------------------------------------------+
| XTERM.JS: The Critical Gap |
+-----------------------------------------------------------------------+
| |
| Write Buffer Configuration: |
| |
| Discard watermark: ~50 MB |
| Write timeout: 12ms between writes |
| |
| The Gap: |
| |
| Callback fires AFTER parser processes data |
| Callback does NOT wait for DOM render |
| |
| Timeline: |
| |
| write(data) --> parse --> callback() --> ... --> DOM render |
| | | |
| | | |
| fires here happens later |
| |
| Result: No feedback loop exists |
| |
+-----------------------------------------------------------------------+
Kitty Analysis
Copy
+-----------------------------------------------------------------------+
| KITTY: Best Native Backpressure |
+-----------------------------------------------------------------------+
| |
| POLLIN Control Pattern: |
| |
| Parser has space? --> Enable POLLIN (accept data) |
| Parser full? --> Disable POLLIN (pause data) |
| |
| This is the best native backpressure: |
| |
| + Controls data intake at OS level |
| + Prevents parser buffer overflow |
| |
| Still not render-synchronized: |
| |
| X Parser space != render completion |
| X Buffer-based, not frame-based |
| |
+-----------------------------------------------------------------------+
Traditional vs MonoTerm
Copy
+-----------------------------------------------------------------------+
| OPEN LOOP: Traditional Terminals |
+-----------------------------------------------------------------------+
| |
| PTY Data |
| | |
| v |
| Parser |
| | (callback or event) |
| v |
| Renderer Queue |
| | |
| v |
| DOM/GPU Render |
| | |
| v |
| [NOTHING SENT BACK] <-- No feedback to producer |
| |
| Producer continues at full speed regardless of consumer state |
| |
+-----------------------------------------------------------------------+
+-----------------------------------------------------------------------+
| CLOSED LOOP: MonoTerm |
+-----------------------------------------------------------------------+
| |
| PTY Data |
| | |
| v |
| VTE Parser (Alacritty) |
| | |
| v |
| AtomicState.pull() [waiting_ack?] |
| | |
| +-- YES --> return None (skip emit, continue parsing) |
| | |
| +-- NO --> emit GridUpdate |
| | |
| v |
| Frontend receives |
| | |
| v |
| inject() to xterm.js |
| | |
| v |
| [Success?] |
| | |
| +-- YES --> grid_ack() --> waiting_ack = false |
| | |
| +-- NO --> No ACK (backend timeout retry) |
| |
| Consumer controls producer speed through ACK after render |
| |
+-----------------------------------------------------------------------+
Verification Result
Copy
+-----------------------------------------------------------------------+
| Q.E.D: PROVEN |
+-----------------------------------------------------------------------+
| |
| Claim: |
| "MonoTerm is the only terminal with consumer-driven flow control" |
| |
| Method: |
| Direct source code analysis of 6 major terminals |
| |
| Findings: |
| |
| Alacritty --> No flow control |
| Ghostty --> Queue-based buffering |
| xterm.js --> Parser buffer limits |
| Kitty --> Parser buffer limits (best) |
| WezTerm --> Time-based coalescing |
| Hyper --> Inherits xterm.js limitations |
| |
| None gate data emission based on render completion. |
| |
| Only MonoTerm: ACK mechanism gates emission after inject success |
| |
+-----------------------------------------------------------------------+
Related Research
- Analysis Methodology - How we conducted the research
- Architecture Diagrams - Visual flow comparisons
- Prior Art - What we learned from each terminal