tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1471Shell 174Rust 105Markdown 943556 Sutichaykuna

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>

03bdd41b4acfc121c9d5ef12d3343b866c6d8f6a · ruwaq sergio · (2 killa ñawpaq) · tayta 609fabdb7 · kay commitpi sach'ata qhaway

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