fix(whp-gui): WLR_LIBINPUT_NO_DEVICES=1 — root-cause the intermittent WHP GUI boot race#122
Merged
Merged
Conversation
…t devices Root-causes the intermittent WHP GUI boot failure noted in #120 (guest-agent exits 1 ~0.45s into boot, before any frame; ~1 in 3 boots). Investigation: guest-agent's own stderr is invisible on the WHP serial console (init redirects to hvc0/ttyS0 but `quiet` drops console_loglevel to 4, so only init's `<0>` kmsg `report()` shows). Added a `note()` that mirrors GUI-startup diagnostics to `/dev/kmsg` at `<2>` (KERN_CRIT, prints under `quiet`) — and crucially, captured cage's stderr (`Stdio::piped`) and forward it to kmsg when cage dies during startup. Two kmsg subtleties bit the instrumentation first and are handled: each write() to /dev/kmsg is one record, so the line is built and written with a single `write_all` (`writeln!`/write_fmt splits into multiple records, and the message-body record lacked the `<N>` prefix so `quiet` hid it); and the priority must be `< 4`. With that, a captured failure showed the real cause: cage: [ERROR] libinput initialization failed, no input devices cage: [ERROR] Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check cage: [ERROR] Failed to initialize backend / Unable to start the wlroots backend and `starting cage (dri card present=true)` — so /dev/dri was fine; wlroots' libinput backend aborts when zero input devices exist yet. In the micro-VM the virtio-input nodes (/dev/input/event*) are created by udev asynchronously; when cage wins the race it sees no devices and exits → wait_for_socket bails → exit 1. Intermittent = the udev-vs-cage race on input nodes. Fix: `WLR_LIBINPUT_NO_DEVICES=1` in cage's env (wlroots' own recommended flag) — start with zero input devices; they hotplug in via udev afterward. An earlier attempt waited for /dev/dri before cage, but the instrumentation proved dri was never the missing resource, so that was dropped for this one-line real fix. Verified on real WHP hardware (this box): 14/14 consecutive clean boots succeed after the fix (was ~1/3 failing before). The cage-stderr→kmsg observability is kept so future WHP GUI failures are self-diagnosing. No unit test — it's an in-VM udev/device race with no host-testable surface; verification is the boot loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root-causes and fixes the intermittent WHP GUI boot failure flagged in #120 (guest-agent exits 1 ~0.45s into boot, before any frame; ~1 in 3 boots).
Investigation (followed the debugger methodology)
guest-agent's own stderr is invisible on the WHP serial console (init redirects to hvc0/ttyS0, but
quietdrops console_loglevel to 4, so only init's<0>kmsgreport()shows). Addednote()mirroring GUI-startup diagnostics to/dev/kmsgat<2>, and captured cage's stderr (Stdio::piped) → forwarded to kmsg when cage dies during startup. (Two kmsg gotchas bit the instrumentation first: onewrite()= one record, so the line must be built + written with a singlewrite_all—writeln!splits into records and the body record lost its<N>prefix, hidden byquiet; and priority must be< 4.)The captured failure showed the real cause:
plus
starting cage (dri card present=true)— /dev/dri was fine; wlroots' libinput backend aborts when zero input devices exist yet. The virtio-input nodes (/dev/input/event*) are created by udev asynchronously; when cage wins the race it sees no devices and exits →wait_for_socketbails → exit 1. Intermittent = the udev-vs-cage race on input nodes.Fix
WLR_LIBINPUT_NO_DEVICES=1in cage's env — wlroots' own recommended flag: start with zero input devices, they hotplug in via udev afterward. (An earlier attempt waited for/dev/dribefore cage, but the instrumentation proved dri was never the missing resource, so it was dropped for this one-line real fix.)Verification
Real WHP hardware (this box): 14/14 consecutive clean boots succeed after the fix (was ~1/3 failing). The cage-stderr→kmsg observability is kept so future WHP GUI failures self-diagnose. No unit test — it's an in-VM udev/device race with no host-testable surface; the boot loop is the verification. Supersedes the "pre-existing boot race" caveat in #120.
🤖 Generated with Claude Code