gnome: el muro de input NO era libudev-zero — el fd de TakeDevice era bloqueante
Tres cambios de diagnóstico en `gnome-start` que, juntos, dieron el veredicto: 1. SONDA DE INPUT antes de lanzar el shell. `libinput list-devices` hace lo mismo que `init_libinput()` de mutter (udev_new + create_context + assign_seat) pero abriendo el devnode por su cuenta. Volvió con rc=0 y los tres dispositivos listados ⇒ **la hipótesis libudev-zero del runbook queda REFUTADA**: la enumeración por /sys funciona. 2. El volcado POR HILO corría DESPUÉS del `kill -ABRT`, o sea sobre un /proc/<pid>/task que ya no existía: salía vacío. Movido antes. Ahí apareció el dato: `tid 201 [Mutter Input Th] wchan=evdev_read syscall=0`. El hilo de input dormido en un `read()` de evdev dentro del kernel. (El core no servía: gdb no desenrolla a través de musl y devuelve `?? ()` para los 11 hilos no principales.) 3. `MUTTER_DEBUG` es una LISTA DE TÓPICOS (g_parse_debug_string sobre meta_debug_keys), no un booleano: con `1` no encendía nada. Ahora `backend,input,kms`, y el tópico `backend` imprime la última línea antes del cuelgue: «Opening and taking control of device file '/dev/input/event0'». Más: ping D-Bus a login1 en el diagnóstico (el daemon respondía: no estaba tildado) y copia de los logs de /tmp —que es tmpfs— a la raíz ext4 para poder sacarlos con debugfs junto al core. La causa está arreglada en tawasuyu (3dd88f582): `TakeDevice` abría sin `O_NONBLOCK`. Receta re-pineada a 2445fa31c y re-sellada b3:7ffa9256. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
2 qillqakuna · +71 −11
diff --git a/recipes/arje-logind-compat.toml b/recipes/arje-logind-compat.toml
index 1c3567ad..95a1f148 100644
--- a/recipes/arje-logind-compat.toml
+++ b/recipes/arje-logind-compat.toml
@@ -29,7 +29,7 @@ version = "0.0.1"
[source]
# El `commit` es el identificador inmutable (la URL es sólo locator, no entra al hash).
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
-commit = "e65e943ef8f6fa77ea9b8565f5d73d9f511ab0df"
+commit = "2445fa31c1b3d8b7da037d2434ace976e2444df4"
# El monorepo COMMITEA su propio `vendor/` — `[patch.crates-io] smithay = { path = "vendor/smithay" }`,
# una copia parcheada de smithay que mirada necesita para el tearing. `cargo vendor` de hammer escribe
# en `vendor/` por defecto y lo pisaba: el build moría con
diff --git a/scripts/gnome/gnome-start-qemu.sh b/scripts/gnome/gnome-start-qemu.sh
index 4102caca..5c0ba981 100755
--- a/scripts/gnome/gnome-start-qemu.sh
+++ b/scripts/gnome/gnome-start-qemu.sh
@@ -17,6 +17,12 @@ export PATH=/usr/bin:/bin:/usr/sbin:/sbin
[ -r /etc/gnome-mode ] && . /etc/gnome-mode
say() { echo "== gnome-qemu :: $*" | tee -a /dev/console /dev/ttyS0 2>/dev/null; }
dump() { echo "---- $1 ----" > /dev/ttyS0 2>/dev/null; cat "$1" > /dev/ttyS0 2>/dev/null; }
+# OJO con el test de vivo: `kill -0` TIENE ÉXITO sobre un ZOMBI (el hijo existe como PID hasta que
+# el padre lo cosecha, y acá el padre es este script, que sólo hace wait al final). La primera
+# versión usaba kill -0 y por eso reportó "sin wayland-0 tras 45s" cuando en realidad gnome-shell ya
+# había muerto en el primer segundo: el diagnóstico decía "0 hilos" porque no quedaba proceso, sólo
+# la entrada zombi. Se mira el State de /proc en su lugar.
+alive() { s=$(sed -n 's/^State:[[:space:]]*//p' /proc/$1/status 2>/dev/null); case "$s" in ""|Z*) return 1;; *) return 0;; esac; }
export LD_LIBRARY_PATH=/usr/lib:/lib:/usr/lib/gnome-shell:/usr/lib/mutter-16
# GI_TYPELIB_PATH es EL env crítico de esta sesión, y el que no tiene análogo en KDE: gnome-shell es
@@ -63,7 +69,11 @@ export MUTTER_DEBUG_SEND_KMS_MODIFIERS=0
if [ "${DIAG:-1}" = 1 ]; then
export G_MESSAGES_DEBUG=all
- export MUTTER_DEBUG=1
+ # MUTTER_DEBUG es una LISTA DE TÓPICOS (g_parse_debug_string sobre meta_debug_keys, core/util.c:42),
+ # no un booleano: con `1` no matcheaba ninguna clave y no encendía nada. `backend` es el que
+ # imprime «Opening and taking control of device file '<path>'» por cada dispositivo que pasa por
+ # MetaDevicePool ⇒ dice EXACTAMENTE en cuál se queda parada la hebra de input.
+ export MUTTER_DEBUG=backend,input,kms
export EGL_LOG_LEVEL=debug
export LIBGL_DEBUG=verbose
fi
@@ -179,6 +189,35 @@ if [ "${DIAG:-1}" = 1 ]; then
fi
say "typelibs visibles: $(ls /usr/lib/girepository-1.0/*.typelib 2>/dev/null | wc -l) sistema + $(ls /usr/lib/gnome-shell/*.typelib 2>/dev/null | wc -l) del shell"
+
+# ── SONDA DE INPUT — barata, y separa las dos hipótesis del muro ────────────────────────────────
+# El muro es la hebra de input de mutter: arranca y nunca señala `input_thread_initialized`.
+# `libinput list-devices` hace EXACTAMENTE lo que hace `init_libinput()` —udev_new +
+# libinput_udev_create_context + libinput_udev_assign_seat("seat0")— pero con `open()/close()`
+# pelados en vez del `TakeDevice` de logind. O sea que discrimina:
+# · la sonda cuelga o no lista nada ⇒ el muro es libudev-zero/libinput (enumeración por /sys)
+# · la sonda lista los dispositivos ⇒ libinput anda; el cuelgue está del lado de mutter
+# (MetaDevicePool → TakeDevice, o algo anterior en el hilo: input settings, keymap)
+# Ojo: `libinput` es un multiplexor de subcomandos y `list-devices` NO es interactivo, pero igual se
+# le pone reloj — si el problema es un cuelgue, la sonda cuelga también, y hay que matarla.
+say "sonda: /sys/class/input = $(ls /sys/class/input 2>/dev/null | tr '\n' ' ')"
+say "sonda: /dev/input = $(ls /dev/input 2>/dev/null | tr '\n' ' ')"
+if [ -x /usr/bin/libinput ]; then
+ ( libinput list-devices >/tmp/libinput-devices.log 2>&1; echo "rc=$?" >>/tmp/libinput-devices.log ) &
+ LI_PID=$!
+ i=0
+ while [ $i -lt 24 ] && alive $LI_PID; do i=$((i+1)); sleep 0.5; done
+ if alive $LI_PID; then
+ say "!! SONDA COLGADA: 'libinput list-devices' no volvió en 12s ⇒ el muro ES libinput/libudev-zero"
+ say " wchan=$(cat /proc/$LI_PID/wchan 2>/dev/null) syscall=$(cat /proc/$LI_PID/syscall 2>/dev/null)"
+ kill -9 $LI_PID 2>/dev/null
+ else
+ say "sonda 'libinput list-devices' VOLVIÓ (no cuelga) — dispositivos:"
+ dump /tmp/libinput-devices.log
+ fi
+else
+ say "sonda: no hay /usr/bin/libinput en la imagen"
+fi
# GNOME_MODE=headless — EXPERIMENTO DECISIVO, no un modo de producción. El backend headless de
# mutter crea el seat con META_SEAT_NATIVE_FLAG_NO_LIBINPUT, o sea que SALTEA `init_libinput()`,
# que es justo el último paso del hilo de input antes de señalar `input_thread_initialized`
@@ -194,12 +233,6 @@ SHELL_PID=$!
# stream EN VIVO al serial (busybox sed no soporta -u ⇒ tail -f directo, sin pipes).
( echo "==== gnome-shell.log (stream vivo) ===="; tail -f /tmp/gnome-shell.log ) > /dev/ttyS0 2>/dev/null &
-# OJO con el test de vivo: `kill -0` TIENE ÉXITO sobre un ZOMBI (el hijo existe como PID hasta que
-# el padre lo cosecha, y acá el padre es este script, que sólo hace wait al final). La primera
-# versión usaba kill -0 y por eso reportó "sin wayland-0 tras 45s" cuando en realidad gnome-shell ya
-# había muerto en el primer segundo: el diagnóstico decía "0 hilos" porque no quedaba proceso, sólo
-# la entrada zombi. Se mira el State de /proc en su lugar.
-alive() { s=$(sed -n 's/^State:[[:space:]]*//p' /proc/$1/status 2>/dev/null); case "$s" in ""|Z*) return 1;; *) return 0;; esac; }
i=0
while [ $i -lt 240 ]; do
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && break
@@ -222,15 +255,42 @@ else
say "syscall: $(cat /proc/$SHELL_PID/syscall 2>/dev/null)"
say "fds abiertos:"; ls -l /proc/$SHELL_PID/fd 2>/dev/null > /dev/ttyS0
say "hilos: $(ls /proc/$SHELL_PID/task 2>/dev/null | wc -l)"
+ # POR HILO, y ANTES del SIGABRT. La primera versión hacía este bucle DESPUÉS de abortar, o sea
+ # sobre un /proc/<pid>/task que ya no existía: salía vacío y no dijo nada. Es el dato más barato
+ # que hay para ubicar la «Mutter Input Thread», porque el core no sirve: gdb no puede desenrollar
+ # a través de musl (sin CFI) y devuelve `?? ()` para los 11 hilos que no son el principal.
+ say "--- por hilo (comm / wchan / syscall) ---"
+ for t in $(ls /proc/$SHELL_PID/task 2>/dev/null); do
+ say " tid $t [$(cat /proc/$SHELL_PID/task/$t/comm 2>/dev/null)] wchan=$(cat /proc/$SHELL_PID/task/$t/wchan 2>/dev/null) syscall=$(cut -d' ' -f1 /proc/$SHELL_PID/task/$t/syscall 2>/dev/null)"
+ done
+ # ¿Sigue vivo y respondiendo el login1? Si el shell está esperando una respuesta D-Bus que no
+ # llega, esto lo separa en dos: daemon muerto/colgado vs daemon vivo que ya contestó.
+ say "arje-logind-compat: pids=$(pgrep -f arje-logind-compat 2>/dev/null | tr '\n' ' ')"
+ for p in $(pgrep -f arje-logind-compat 2>/dev/null); do
+ say " logind pid $p state=$(sed -n 's/^State:[[:space:]]*//p' /proc/$p/status 2>/dev/null) wchan=$(cat /proc/$p/wchan 2>/dev/null)"
+ done
+ ( dbus-send --system --print-reply --dest=org.freedesktop.login1 \
+ /org/freedesktop/login1 org.freedesktop.DBus.Properties.Get \
+ string:org.freedesktop.login1.Manager string:NAutoVTs >/tmp/login1-ping.log 2>&1
+ echo "rc=$?" >>/tmp/login1-ping.log ) &
+ PING_PID=$!
+ i=0; while [ $i -lt 16 ] && alive $PING_PID; do i=$((i+1)); sleep 0.5; done
+ if alive $PING_PID; then
+ say "!! login1 NO responde (ping D-Bus colgado 8s) ⇒ el daemon se quedó tildado"
+ kill -9 $PING_PID 2>/dev/null
+ else
+ say "login1 responde al ping D-Bus:"; dump /tmp/login1-ping.log
+ fi
+ # /tmp es tmpfs ⇒ el log del daemon se pierde con la VM. Copiarlo a la raíz ext4, que sí se
+ # sincroniza y se puede sacar con debugfs junto al core.
+ cp /tmp/logind-compat.log /logind-compat.log 2>/dev/null || true
+ cp /tmp/gnome-shell.log /gnome-shell.log 2>/dev/null || true
# Sin gdb en la imagen, la única forma de ver DÓNDE está bloqueado es forzarle un core y leerlo
# con el gdb del host (`thread apply all bt`). SIGABRT lo produce y no lo maneja nadie.
say "forzando core del proceso colgado (SIGABRT)..."
kill -ABRT $SHELL_PID 2>/dev/null
sleep 12; sync; sync
say "cores: $(ls -la /core.* 2>/dev/null | tr '\n' ' ' || echo NINGUNO)"
- for t in $(ls /proc/$SHELL_PID/task 2>/dev/null); do
- say " tid $t wchan=$(cat /proc/$SHELL_PID/task/$t/wchan 2>/dev/null) comm=$(cat /proc/$SHELL_PID/task/$t/comm 2>/dev/null)"
- done
exec /bin/sh
fi
export WAYLAND_DISPLAY=wayland-0