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>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user