gnome: 🏔 EL COMPOSITOR SUBE ENTERO SOBRE DRM REAL — cae el muro de input

Con el `O_NONBLOCK` de TakeDevice (tawasuyu 3dd88f582, receta re-sellada
b3:7ffa9256), gnome-shell arranca en QEMU sobre el backend nativo KMS, no headless:

  BACKEND: Opening and taking control of device file '/dev/input/event0'  (y event2, event1)
  BACKEND: Realizing stage 'MetaStageNative'
  KMS: Plane 33 … primary for CRTC 37 · Plane 34 … cursor
  Using Wayland display name 'wayland-0'
  == gnome-qemu :: compositor OK (wayland-0) — el shell ES el display server

El muro gráfico que este runbook anunciaba como «el que viene después» NUNCA
APARECIÓ: los fixes que pagó la campaña KDE y quedaron precargados en
gnome-start-qemu.sh alcanzaron tal cual. mutter crea el renderer gbm y elige card0
como primaria sin quejarse.

Queda un solo muro, y no es un cuelgue: el shell sale con código 1 en
`Requiring AccountsService` — una dep de RUNTIME que la receta ya tiene medida
símbolo por símbolo.

El runbook además CORRIGE su propio diagnóstico anterior (culpaba a libudev-zero) y
deja escrito cómo se refutó, que es lo reusable: una sonda que hace lo mismo que el
código sospechado pero por otro camino, y /proc por hilo ANTES de abortar —porque
gdb no desenrolla a través de musl y el core sólo da `?? ()`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-29 11:23:06 -04:00
co-authored by Claude Opus 5
parent 03bdd41b4a
commit b01fad94e5
+79 -34
View File
@@ -1,9 +1,21 @@
# Runbook — arrancar gnome-shell en QEMU (y dónde está el muro hoy)
Estado al 2026-07-29: **gnome-shell arranca, toma el DRM master y los dispositivos de input por
logind, y queda BLOQUEADO esperando que termine de inicializarse la hebra de input de mutter.** El
SIGSEGV que había antes está arreglado (dos bugs reales de `arje-logind-compat`, abajo). Nada de
esto es un misterio pendiente de diagnosticar: cada muro está localizado por backtrace.
Estado al 2026-07-29: **el compositor SUBE ENTERO sobre DRM real.** gnome-shell toma el DRM master
y los tres dispositivos de input por logind, realiza el stage `MetaStageNative`, asigna los planos
primario y de cursor, y expone `wayland-0`:
```
BACKEND: Opening and taking control of device file '/dev/input/event0' ← y event2, y event1
BACKEND: Realizing stage 'MetaStageNative'
KMS: Plane 33 … primary for CRTC 37 · Plane 34 … cursor
Using Wayland display name 'wayland-0'
== gnome-qemu :: compositor OK (wayland-0) — el shell ES el display server
```
Lo único que queda para tener escritorio es la **capa JS**: el shell sale con código 1 en
`JS ERROR: Requiring AccountsService, version 1.0: Typelib file … not found`. Ya no hay ningún
cuelgue ni ningún SIGSEGV: los tres muros anteriores están cerrados, cada uno por medición y no por
conjetura.
Hermano de [`kde-qemu-desktop.md`](kde-qemu-desktop.md), del que reusa el andamiaje: la base
`work/metal-rootfs`, la inyección de mesa-llvmpipe/LLVM/musl, el truco del console-getty y el propio
@@ -36,35 +48,63 @@ gdb -batch -q -ex "set sysroot $PWD/work/gnome-qemu-rootfs" \
-ex "core-file /tmp/core.gnome-shell" -ex "bt 25" work/gnome-qemu-rootfs/usr/bin/gnome-shell
```
## EL MURO DE HOY — la hebra de input de mutter
## EL MURO DE HOY — el typelib de AccountsService
```
#5 g_cond_wait glib/gthread.c:1686
#7 meta_seat_impl_initable_init src/backends/native/meta-seat-impl.c:3154
#8 meta_seat_native_constructed src/backends/native/meta-seat-native.c:146
#12 meta_backend_native_create_default_seat
#14 init_clutter src/backends/meta-backend.c:1293
Gjs-CRITICAL: JS ERROR: Error: Requiring AccountsService, version 1.0:
Typelib file for namespace 'AccountsService', version '1.0' not found
Execution of main.js threw exception → gnome-shell sale con código 1
```
El hilo principal arranca la «Mutter Input Thread» y **espera en un condvar a que ésa avise que
terminó de inicializarse. Nunca avisa.** El proceso queda vivo e inmóvil: 12 hilos, `State: S`,
`wchan=futex_do_wait`, con `/dev/dri/card0` abierto TRES veces y `/dev/input/event0` abierto — o sea
que el `TakeDevice` de logind YA funciona y el compositor tiene DRM master e input. Lo que no cierra
es la inicialización del asiento de libinput.
No es un cuelgue: es una dep de RUNTIME que falta. La receta está escrita y medida en
`recipes/incoming-gnome/accountsservice.toml` y **no sella todavía** por dos huecos de NUESTRA capa
de compatibilidad, contados símbolo por símbolo en el comentario de esa receta: ocho símbolos
`sd-*` que `libelogind` no exporta (los cinco `sd_login_monitor_*` son una API de notificación, no
getters) y `fgetspent_r`, que es extensión de glibc y musl no tiene.
**Hipótesis principal, y no es nueva en este repo: `libudev-zero`.** `libinput_udev_assign_seat()`
enumera y monitorea por udev, y el rootfs no trae udev de verdad. Ya hubo un episodio idéntico en
otro frente —«input muerto = eudev pisó libudev-zero», ver [[mirada-usb-nvidia]]— así que el próximo
paso es mirar por ahí antes que en mutter.
## CÓMO CAYÓ EL MURO ANTERIOR — la hebra de input (cerrado 2026-07-29)
Para volver a sacar este backtrace: el `gnome-start` **le fuerza un core al proceso colgado con
SIGABRT** después del timeout (sin gdb en la imagen es la única forma de ver dónde está parado), y
lo deja en la raíz con `sync`.
Vale la pena dejarlo escrito porque **el diagnóstico que había acá era falso** y la forma de
refutarlo es reusable.
## LO QUE YA SE ARREGLÓ (dos bugs reales en arje-logind-compat)
Decía: «el hilo principal espera en un condvar a que la Mutter Input Thread avise que terminó de
inicializarse; nunca avisa» —eso era correcto— «hipótesis principal: `libudev-zero`, que
`libinput_udev_assign_seat()` enumera por udev y el rootfs no trae udev de verdad». Eso era la
conjetura, apoyada en un episodio parecido de otro frente ([[mirada-usb-nvidia]]).
Ambos encontrados arrancando esta imagen, ambos con test, ambos **locales todavía — falta
commitear/pushear tawasuyu y re-pinear la receta**:
**La sonda que la refutó**: `libinput list-devices`, que hace exactamente lo que hace
`init_libinput()` de mutter —`udev_new` + `libinput_udev_create_context` +
`libinput_udev_assign_seat("seat0")`—. Volvió con `rc=0` y los tres dispositivos listados. La
enumeración por /sys con libudev-zero funciona perfecto. Está horneada en `gnome-start` y corre en
cada arranque, antes del shell.
**El dato que dio la causa**: `tid 201 [Mutter Input Th] wchan=evdev_read syscall=0`. El hilo estaba
dormido en un `read()` de evdev DENTRO DEL KERNEL. Ese volcado por hilo ya estaba en el script pero
corría *después* del `kill -ABRT`, sobre un `/proc/<pid>/task` que ya no existía: salía vacío y no
decía nada. El core tampoco servía — gdb no desenrolla a través de musl y devuelve `?? ()` para los
11 hilos que no son el principal. **Acá `/proc` le gana al core.**
**La causa**: `arje-logind-compat` abría el device de `TakeDevice` sin `O_NONBLOCK`. El compositor
no elige los flags —recibe el fd ya abierto por el bus—, y libinput asume no-bloqueante para poder
leer en bucle hasta `EAGAIN`; lo dice donde abre (`libinput/src/evdev.c:2401`) y le pasa
`O_RDWR|O_NONBLOCK|O_CLOEXEC` a `open_restricted()`, pero mutter, cuando hay logind, ignora esos
flags y delega la apertura. systemd-logind abre con `O_NONBLOCK`, así que la dependencia no se nota
hasta que la implementa otro. Arreglado en tawasuyu `3dd88f582`, con test.
Y por qué la sonda no lo veía: `libinput list-devices` abre el devnode **él mismo**, con
`O_NONBLOCK`. Sólo el camino por logind pasaba por el fd malo. Esa asimetría es justamente lo que la
convirtió en un experimento y no en una repetición.
Tres perillas de diagnóstico que quedaron y valen para el próximo muro:
`MUTTER_DEBUG` es una **lista de tópicos** (`g_parse_debug_string` sobre `meta_debug_keys`,
`src/core/util.c:42`), no un booleano — con `1` no encendía nada; con `backend` imprime
«Opening and taking control of device file '<path>'» por cada device y dice en cuál se para. El ping
D-Bus a login1 separa «daemon tildado» de «daemon vivo que ya contestó». Y los logs de `/tmp` (tmpfs)
se copian a la raíz ext4 antes de abortar, para sacarlos con `debugfs` junto al core.
## LO QUE YA SE ARREGLÓ ANTES (dos bugs reales en arje-logind-compat)
Ambos encontrados arrancando esta imagen, ambos con test, ambos ya en tawasuyu y sellados:
1. **La sesión se creaba PEREZOSAMENTE.** `ensure_user` sólo corría dentro de un método del Manager,
y `write_login_state` vive adentro. Pero mutter no empieza por D-Bus: lo primero que hace es
@@ -87,14 +127,19 @@ De paso, un arreglo de portabilidad musl preexistente: `libc::ioctl` toma `c_ulo
systemd) el launcher de sesión lo prende. Default off» — y el launcher es `gnome-start`. El puente
que escribía `/run/systemd/` a mano fue reinventar esa perilla; queda como fallback inerte.
El muro gráfico que este runbook listaba como «el que viene después» **nunca apareció**: los fixes
que KDE dejó pagos y precargados en `gnome-start-qemu.sh` (`GBM_ALWAYS_SOFTWARE`, `kms_swrast`,
`LP_NUM_THREADS=1`, `MUTTER_DEBUG_SEND_KMS_MODIFIERS=0`) alcanzaron: mutter crea el renderer gbm y
elige `/dev/dri/card0` como primaria sin quejarse. Es el rédito directo de la campaña anterior.
## Lo que falta, en orden
1. **La hebra de input de mutter** (el muro de hoy): mirar `libudev-zero` primero.
2. **Commitear y pushear tawasuyu** con los dos arreglos de arje-logind-compat, y re-pinear el
`commit` de `recipes/arje-logind-compat.toml` para sellar el artefacto de verdad. Hoy la imagen
corre un binario compilado a mano vía `ALC_BIN=`, que **no es reproducible**.
3. **Empaquetar la política D-Bus de login1** dentro del artefacto de arje-logind-compat.
4. Arreglar el `identity mismatch` del `Announce` al bus del fractal (hoy sólo un WARN).
5. Recién después: el muro gráfico (GBM/EGL software sobre virtio-gpu), donde KDE ya dejó los fixes
pagos y precargados en `gnome-start-qemu.sh` (`GBM_ALWAYS_SOFTWARE`, `kms_swrast`,
`LP_NUM_THREADS=1`, `MUTTER_DEBUG_SEND_KMS_MODIFIERS=0`).
1. **`AccountsService`** (el muro de hoy): cerrar los ocho símbolos `sd-*` en `arje-sdlogin-compat`
y `fgetspent_r`, sellar `accountsservice`, y hidratar su typelib. Ojo al costo: re-sellar
`libelogind` re-hashea todo lo que lo declara (mutter, gnome-shell, polkit…) ⇒ pasar
`yupana radio libelogind` ANTES de tocarlo.
2. **Empaquetar la política D-Bus de login1** dentro del artefacto de arje-logind-compat (hoy la
escribe el script de imagen).
3. Arreglar el `identity mismatch` del `Announce` al bus del fractal (hoy sólo un WARN).
4. Con la capa JS viva: validar CON PANTALLA (`DISP=gtk`), nunca sólo por serial — regla heredada de
KDE ([[metal-dual-desktop-en-curso]]).