_emit() wrote to stdout synchronously from QEMU callback context — the iothread fires _on_uart_tx per UART byte, each becoming ~45 bytes of JSON. When the parent's pipe reader stalled, the 64 KB pipe filled and the write blocked INSIDE the QEMU iothread, freezing the entire guest. Observed as an intermittent (~1 in 10) boot hang: serial output stops right after the ROM log / rtcinit line — exactly where the accumulated boot events cross the pipe capacity — and never recovers. Direct worker harness runs (fast reader) never reproduced it; the browser/WS path did. Route _emit() through a bounded queue drained by a dedicated writer thread (opportunistic batching, one write per drain). Under extreme backpressure events are dropped and counted on stderr — losing telemetry beats freezing the emulated CPU. The shutdown path posts a sentinel and joins the writer so crash/system events still flush before os._exit. Verified on staging: 10/10 UI run/stop cycles + 8/8 direct harness boots with identical serial latency (~0.95s to first app output). |
||
|---|---|---|
| .. | ||
| api | ||
| core | ||
| database | ||
| mcp | ||
| models | ||
| schemas | ||
| services | ||
| utils | ||
| __init__.py | ||
| main.py | ||