Estoy usando Ubuntu 14.04 y estoy experimentando este comportamiento que parece que no puedo entender:
- Ejecute el
yescomando (en el shell predeterminado: Bash ) - Escribe CtrlZpara detener
yes - Ejecutar
jobs. Salida:
[1]+ Stopped yes - Corre
kill -9 %1para detenerteyes. Salida:
[1]+ Stopped yes - Ejecutar
jobs. Salida:
[1]+ Stopped yes
Esto está en Ubuntu 3.16.0-30-genericejecutándose en una máquina virtual paralela.
¿Por qué mi kill -9comando 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 yesla segunda terminal inmediatamente da esto en layesterminal:En consecuencia, si
kill -9 %1no finaliza el proceso de inmediato, entoncesbashno está enviando la señal hasta que se realizafgel 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 laSIGCONTseñal que descongela el proceso) y, por lo tanto, evita que el proceso se elimine de inmediato.SIGTERMestá bloqueado, peroSIGKILLno lo está. De todos modos, según un comentario de OP, el problema parece ser quejobsno detecta que el proceso ha muerto, no el proceso por el que no está siendo asesinadokill -9 %1.SIGKILLno 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,SIGKILLno 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
yesse detuvoSIGTSTPy acaba de ejecutar elkillcomando con el shell Bourne Again:SIGKILLalyesproceso.yesproceso 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:
killcomando incorporado , marca la entrada en su tabla de trabajo como que necesita un mensaje de notificación impreso en el siguiente punto disponible.killcomando y, justo antes de imprimir, la solicitud vuelve a comprobar si debe imprimir mensajes de notificación sobre cualquier trabajo.yesproceso 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.yesproceso se programa y se suicida.Los puntos importantes son:
SIGKILLno 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 respuestaSIGKILLsea 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.killvez por elSIGCHLDcontrolador de señal. Esto significa que uno puede ver dos mensajes si el shell se está ejecutando antes delyesproceso que se reprograma para suicidarse; uno un mensaje "Detenido" y otro un mensaje "Muerto"./bin/killprograma 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 elSIGCHLDcontrolador.killelyesproceso desde otro shell.fuente
jobsy el shell todavía ve el proceso como vivo. Esa sería una condición de carrera de programación inusualmente larga. :)jobscomandos de multiplicación después de lokillcual todos todavía indican que el proceso se ha detenido. Sin embargo, me inspiró a seguir experimentando y descubrí esto: el mensaje[1]+ Terminated yesse imprime tan pronto como ejecuto otro comando externo (no un shell integrado comoechoojobs). Entonces puedo correrjobstanto como quiera y sigue imprimiendo[1]+ Stopped yes. Pero tan pronto como corro,lspor ejemplo, Bash imprime[1]+ Terminated yesjobsno 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 -pe intente matarlo comoroot.fuente
killcomando 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á elkillcomando real y no el bash incorporado.which kill /usr/bin/killwhichno es un bash-builtin, porwhich <anything>lo que siempre le dará la ruta al comando real. Pero intente compararkill --helpvs/usr/bin/kill --help.kill.Lo que estás observando es un error en esta versión de bash.
kill -9 %1mata el trabajo de inmediato. Puedes observar eso conps. Puede rastrear el proceso bash para ver cuándokillse 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
waitsistema 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
killcomando, pero eso no está garantizado, porque hay una condición de carrera. Las señales se entregan de forma asíncrona: lakillllamada 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 (wait4no 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 (psinforma 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