Repository navigation
docs: design & work plan for native virtual display on Linux - #3
Merged
Merged
Conversation
The flagship feature of this fork. Grounds the plan in (a) the actual approach of Apollo PR ClassicOldSong#1477 (EDID-override via debugfs on a disconnected DRM connector, captured by kmsgrab — no kernel module, no evdi) and (b) a map of Apollo's Linux capture/display code and the exact integration points (misc.cpp display() selector, the process.cpp #ifdef _WIN32 bifurcation, the nvhttp.cpp capability flag, libdisplaydevice nullptr on Linux). Defines the chosen approach (adopt/finish ClassicOldSong#1477 + a pluggable pre_probe_cmd fallback per Sunshine #4762 for headless/no-free-connector cases), a phased work plan (Phase 0 reproduce & settle the wlr-vs-KMS capture question → client capability parity → lifecycle+HDR hardening → pluggable fallback → monitor orchestration), a risk register, a testing matrix, and open questions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
unjordi
added a commit
that referenced
this pull request
Jul 28, 2026
`proc_t::terminate()` es alcanzable desde al menos CUATRO hilos sin ninguna
sincronizacion, y recorre `_app_prep_it`, que es estado MIEMBRO:
- hilo del system tray (system_tray.cpp:98,137,144,456)
- hilo HTTPS de la config web (confighttp.cpp:894,1184,1235)
- hilo HTTPS de nvhttp, via el endpoint /cancel -> rtsp_stream::terminate_sessions()
- la ruta de teardown de sesion (process.cpp)
Escenario que se dispara solo: al cerrar el stream, el cliente manda /cancel por
HTTP mientras la ruta de desconexion ya esta terminando la app. Los dos
`terminate()` recorren el mismo cursor -> los undo prep-cmds se ejecutan DOS
VECES y el iterador se pasa de `_app_prep_begin` -> SIGSEGV.
No es una carrera estrecha: el `child.wait()` del bucle es bloqueante, asi que la
ventana dura segundos.
Capturado en vivo (2026-07-28), hilo `nvhttp::47984`:
#0 proc::proc_t::terminate(bool, bool) <-- SIGSEGV (SEGV_MAPERR)
#1 stream::session::join(session_t&)
#2 rtsp_stream::terminate_sessions()
#3 nvhttp::cancel(Response, Request)
...
#13 std::thread ... nvhttp::start()
con el sintoma delator en el log: "Executing Undo Cmd" DOS veces, 0.8 s aparte.
Tres crashes en dos dias en el mismo host (2 x SIGSEGV + 1 x SIGTRAP).
Consecuencia grave: cuando el daemon muere a media terminacion, los undo que
faltaban NO corren. En un host con un prep-cmd que bloquea la sesion al
desconectar, eso deja la MAQUINA DESBLOQUEADA.
Cambios:
1. `std::recursive_mutex` compartido, tomado en execute(), pause(), terminate(),
launch_input_only() y refresh(). Recursivo porque pause() reentra por
terminate() cuando terminate_on_pause esta activo.
Es `static inline` a proposito: `proc_t` se move-asigna al recargar apps.json
(`proc = std::move(*proc_opt)`), y un mutex miembro eliminaria el move
assignment defaulted. Ademas asi el lock sobrevive esa recarga, que es
justamente la otra mitad de la carrera.
2. Guarda de idempotencia `_terminating`: una segunda llamada concurrente sale
sin repetir los undo, en vez de duplicarlos.
3. El bucle de undo recorre un cursor LOCAL y retira el compartido de entrada, de
modo que ninguna otra llamada pueda observar un iterador a medio consumir.
4. Timeout por comando (10 s) en el bucle de undo. Antes, un undo colgado impedia
que corrieran los siguientes y disparaba el watchdog de sesion ("Hang
detected!"), que mata el daemon — el SIGTRAP de la lista de arriba. Se usa un
bucle de sondeo porque `child::wait_for()` esta roto/deprecado en
Boost.Process v1 (ya documentado en `terminate_process_group`).
Los puntos 1-3 atacan el SIGSEGV; el 4 ataca el SIGTRAP. Son el mismo bucle.
Build verde con gcc-14, Release, cero warnings.
Co-Authored-By: Claude Opus 5 (1M context) <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.
The detailed engineering plan for Helios' flagship feature: a native virtual display on Linux/Wayland that matches the client's resolution/refresh/HDR and tears down on disconnect — parity with the Windows SudoVDA path.
Grounded in research, not hand-waving:
kmsgrab(no kernel module, no evdi). Plus a pluggablepre_probe_cmdfallback (Sunshine #4762) for headless / no-free-connector cases.misc.cpp:955capture selector, theprocess.cpp:236#ifdef _WIN32bifurcation, thenvhttp.cppcapability flag (why Selene says "not supported"),libdisplaydevicereturningnullptron Linux.Doc:
docs/design/virtual-display-linux.md.🤖 Generated with Claude Code