Estoy usando Ubuntu 14.04 y estoy experimentando este comportamiento que parece que no puedo entender:
- Ejecute el
yes
comando (en el shell predeterminado: Bash ) - Escribe CtrlZpara detener
yes
- Ejecutar
jobs
. Salida:
[1]+ Stopped yes
- Corre
kill -9 %1
para detenerteyes
. Salida:
[1]+ Stopped yes
- Ejecutar
jobs
. Salida:
[1]+ Stopped yes
Esto está en Ubuntu 3.16.0-30-generic
ejecutándose en una máquina virtual paralela.
¿Por qué mi kill -9
comando no finalizó el comando sí ? Pensé que SIGKILL no puede ser atrapado o ignorado? ¿Y cómo puedo terminar el comando yes ?
shell
job-control
s1m0n
fuente
fuente
uname -a
) pleaseLinux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
. Estoy ejecutando Ubuntu en Parallels Desktop.(signal)
para que pueda notar la diferencia.Respuestas:
Las señales están bloqueadas para procesos suspendidos. En una terminal:
En una segunda terminal:
En la primera terminal:
Sin embargo
SIGKILL
, no se puede bloquear. Hacer lo mismo conkillall -9 yes
la segunda terminal inmediatamente da esto en layes
terminal:En consecuencia, si
kill -9 %1
no finaliza el proceso de inmediato, entoncesbash
no está enviando la señal hasta que se realizafg
el proceso, o ha descubierto un error en el núcleo.fuente
SIGTSTP
(que es la versión bloqueable deSIGSTOP
) al proceso activo. Esto pone el proceso en un estado congelado donde el núcleo no lo programará. Eso también inhibe el procesamiento de la señal (excepto laSIGCONT
señal que descongela el proceso) y, por lo tanto, evita que el proceso se elimine de inmediato.SIGTERM
está bloqueado, peroSIGKILL
no lo está. De todos modos, según un comentario de OP, el problema parece ser quejobs
no detecta que el proceso ha muerto, no el proceso por el que no está siendo asesinadokill -9 %1
.SIGKILL
no se puede bloquear, no hay garantía de que se entregue en un tiempo significativo. Si un proceso se suspende pendiente de bloqueo de E / S, por ejemplo,SIGKILL
no llegará hasta que el proceso se active. Potencialmente, esto podría ser nunca, si no se produce E / S.No entres en pánico.
No pasa nada funky. No hay error de kernel aquí. Este es un comportamiento perfectamente normal del shell Bourne Again y un sistema operativo multitarea.
Lo que hay que recordar es que un proceso se mata a sí mismo , incluso en respuesta a
SIGKILL
. Lo que está sucediendo aquí es que el shell Bourne Again está dando vueltas a las cosas antes de que el proceso que acaba de decir que se mate se convierta en suicidio.Considere lo que sucede desde el punto donde
yes
se detuvoSIGTSTP
y acaba de ejecutar elkill
comando con el shell Bourne Again:SIGKILL
alyes
proceso.yes
proceso está programado para ejecutarse e inmediatamente se suicida.La razón por la que está viendo una cosa y otras personas están viendo otra es una carrera simple entre dos procesos listos para ejecutarse, cuyo ganador se debe exclusivamente a cosas que varían de una máquina a otra y con el tiempo. La carga del sistema hace la diferencia, al igual que el hecho de que su CPU es virtual.
En el caso interesante, el detalle del paso 2 es el siguiente:
kill
comando incorporado , marca la entrada en su tabla de trabajo como que necesita un mensaje de notificación impreso en el siguiente punto disponible.kill
comando y, justo antes de imprimir, la solicitud vuelve a comprobar si debe imprimir mensajes de notificación sobre cualquier trabajo.yes
proceso aún no ha tenido la oportunidad de suicidarse, por lo que, en lo que respecta al shell, el trabajo aún está en estado detenido. Por lo tanto, el shell imprime una línea de estado de trabajo "Detenido" para ese trabajo y restablece su indicador de notificación pendiente.yes
proceso se programa y se suicida.Los puntos importantes son:
SIGKILL
no es mágico Los procesos verifican si hay señales pendientes cuando se regresa al modo de aplicación desde el modo kernel, que ocurre al final de los fallos de página, las interrupciones (no anidadas) y las llamadas al sistema. Lo único especial es que el núcleo no permite que la acción en respuestaSIGKILL
sea otra cosa que un suicidio inmediato e incondicional, sin volver al modo de aplicación. Es importante destacar que los procesos deben estar haciendo transiciones de modo de núcleo a aplicación y estar programados para ejecutarse a fin de responder a las señales.set -o notify
). Se imprimen la próxima vez que el shell alcanza un punto en su ciclo de ejecución que verifica para ver si hay notificaciones pendientes.kill
vez por elSIGCHLD
controlador de señal. Esto significa que uno puede ver dos mensajes si el shell se está ejecutando antes delyes
proceso que se reprograma para suicidarse; uno un mensaje "Detenido" y otro un mensaje "Muerto"./bin/kill
programa no tiene acceso a la tabla de trabajos internos del shell; así que no verás tal comportamiento con/bin/kill
. El indicador de notificación pendiente solo se establece una vez, por elSIGCHLD
controlador.kill
elyes
proceso desde otro shell.fuente
jobs
y el shell todavía ve el proceso como vivo. Esa sería una condición de carrera de programación inusualmente larga. :)jobs
comandos de multiplicación después de lokill
cual todos todavía indican que el proceso se ha detenido. Sin embargo, me inspiró a seguir experimentando y descubrí esto: el mensaje[1]+ Terminated yes
se imprime tan pronto como ejecuto otro comando externo (no un shell integrado comoecho
ojobs
). Entonces puedo correrjobs
tanto como quiera y sigue imprimiendo[1]+ Stopped yes
. Pero tan pronto como corro,ls
por ejemplo, Bash imprime[1]+ Terminated yes
jobs
no se da cuenta de que el proceso realmente ha muerto ... Sin embargo, no estoy seguro de qué hacer con el estado que se está actualizando ejecutando otro comando.Algo funky puede estar sucediendo en su sistema, en la mía su receta funciona muy bien con y sin
-9
:Obtenga el pid con
jobs -p
e intente matarlo comoroot
.fuente
kill
comando interno de su bash haga un esfuerzo adicional y verifique si el trabajo está congelado (es posible que desee intentar averiguar el PID del trabajo y matarlo usandoenv kill <pid>
. De esa manera usará elkill
comando real y no el bash incorporado.which kill /usr/bin/kill
which
no es un bash-builtin, porwhich <anything>
lo que siempre le dará la ruta al comando real. Pero intente compararkill --help
vs/usr/bin/kill --help
.kill
.Lo que estás observando es un error en esta versión de bash.
kill -9 %1
mata el trabajo de inmediato. Puedes observar eso conps
. Puede rastrear el proceso bash para ver cuándokill
se llama a la llamada del sistema, y rastrear el subproceso para ver cuándo recibe y procesa las señales. Más interesante, puedes ir y ver qué está pasando con el proceso.En otra terminal:
El subproceso es un zombie . Está muerto: todo lo que queda es una entrada en la tabla de procesos (pero no hay memoria, código, archivos abiertos, etc.). La entrada se deja hasta que su padre tome nota y recupere su estado de salida llamando a la llamada del
wait
sistema o a uno de sus hermanos .Se supone que un shell interactivo verifica si hay niños muertos y los cosecha antes de imprimir un mensaje (a menos que esté configurado de otra manera). Esta versión de bash no puede hacerlo en algunas circunstancias:
Puede esperar que bash informe "Muerto" tan pronto como se imprima el mensaje después del
kill
comando, pero eso no está garantizado, porque hay una condición de carrera. Las señales se entregan de forma asíncrona: lakill
llamada del sistema vuelve tan pronto como el núcleo ha descubierto a qué proceso (s) entregar la señal, sin esperar a que se entregue realmente. Es posible, y sucede en la práctica, que bash tenga tiempo para verificar el estado de su subproceso, descubrir que aún no está muerto (wait4
no informa la muerte de ningún niño) e imprimir que el proceso aún se detiene. Lo que está mal es que antes del próximo aviso, la señal se haya entregado (ps
informa que el proceso está muerto), pero bash todavía no ha llamadowait4
(podemos ver eso no solo porque todavía informa que el trabajo está "Detenido", sino porque el zombi todavía está presente en la tabla de proceso). De hecho, bash solo cosecha al zombi la próxima vez que necesite llamarwait4
, cuando ejecuta algún otro comando externo.El error es intermitente y no pude reproducirlo mientras se rastrea bash (presumiblemente porque es una condición de carrera en la que bash debe reaccionar rápidamente). Si la señal se entrega antes de las comprobaciones de bash, todo sucede como se esperaba.
fuente