_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). |
||
|---|---|---|
| .. | ||
| boot_images | ||
| esp-idf-template | ||
| __init__.py | ||
| arduino_cli.py | ||
| asm8080.py | ||
| asmz80.py | ||
| board_access.py | ||
| c_compile.py | ||
| chip_compile.py | ||
| esp32_flash_image.py | ||
| esp32_i2c_slaves.py | ||
| esp32_lib_bridge.py | ||
| esp32_lib_manager.py | ||
| esp32_sd_slave.py | ||
| esp32_signals.py | ||
| esp32_spi_slaves.py | ||
| esp32_worker.py | ||
| esp_qemu_manager.py | ||
| espidf_compiler.py | ||
| gpio_shim.py | ||
| qemu_manager.py | ||
| rom_compile.py | ||
| signal_router.py | ||
| stm32_lib_manager.py | ||
| stm32_worker.py | ||
| wasm_chip_runtime.py | ||
| wasm_chip_slave.py | ||
| wifi_status_parser.py | ||