¿Qué hace un programa cuando se envía la señal SIGKILL?

39

Cuando solía killall -9 namematar un programa, el estado se convirtió en zombie. Algunos minutos después, se detuvo realmente. Entonces, ¿qué está pasando durante esos minutos?

haikun he
fuente

Respuestas:

66

El programa en realidad nunca recibe la señal SIGKILL, ya que SIGKILL es manejado completamente por el sistema operativo / kernel.

Cuando se envía SIGKILL para un proceso específico, el programador del kernel deja de darle a ese proceso más tiempo de CPU para ejecutar el código de espacio de usuario. Si el proceso tiene subprocesos que ejecutan código de espacio de usuario en otras CPU / núcleos en el momento en que el planificador toma esta decisión, esos subprocesos también se detendrán. (En los sistemas de un solo núcleo, esto solía ser mucho más simple: si el único núcleo de la CPU en el sistema ejecutaba el programador, ¡por definición no ejecutaba el proceso al mismo tiempo!)

Si el proceso / subproceso está ejecutando el código del kernel (por ejemplo, una llamada al sistema o una operación de E / S asociada con un archivo mapeado en memoria) en el momento de SIGKILL, se vuelve un poco más complicado: solo algunas llamadas del sistema son interrumpibles, por lo que kernel marca internamente el proceso como un estado especial de "muerte" hasta que se resuelven las llamadas del sistema o las operaciones de E / S. El tiempo de CPU para resolverlos se programará como de costumbre. Las llamadas de sistema interrumpible o las operaciones de E / S comprobarán si el proceso que las llamó se está muriendo en algún punto de detención adecuado, y se cerrará temprano en ese caso. Las operaciones ininterrumpidas se completarán y verificará si hay un estado de "muerte" justo antes de regresar al código de espacio de usuario.

Una vez que se resuelven las rutinas del kernel en proceso, el estado del proceso cambia de "moribundo" a "muerto" y el kernel comienza a limpiarlo, de forma similar a cuando un programa sale normalmente. Una vez que se complete la limpieza, se asignará un código de resultado superior a 128 (para indicar que el proceso fue cancelado por una señal; vea esta respuesta para los detalles desordenados ), y el proceso pasará al estado "zombie" . El padre del proceso cancelado será notificado con una señal SIGCHLD.

Como resultado, el proceso en sí nunca tendrá la oportunidad de procesar realmente la información que ha recibido un SIGKILL.

Cuando un proceso está en un estado "zombie" significa que el proceso ya está muerto, pero su proceso padre aún no lo ha reconocido al leer el código de salida del proceso muerto mediante la wait(2)llamada al sistema. Básicamente, el único recurso que un proceso zombie está consumiendo es una ranura en la tabla de proceso que contiene su PID, el código de salida y algunas otras "estadísticas vitales" del proceso en el momento de su muerte.

Si el proceso padre muere antes que sus hijos, los procesos hijos huérfanos son adoptados automáticamente por el PID # 1, que tiene el deber especial de seguir llamando wait(2)para que los procesos huérfanos no se queden como zombis.

Si el proceso de zombie tarda varios minutos en desaparecer, sugiere que el proceso padre del zombie está luchando o no está haciendo su trabajo correctamente.

Hay una descripción irónica sobre qué hacer en caso de problemas de zombis en sistemas operativos tipo Unix: "No puedes hacer nada por los zombis, ya que ya están muertos. ¡En lugar de eso, mata al malvado maestro zombie! " (es decir, el proceso principal de los zombis problemáticos)

telcoM
fuente
55
¿Qué sucede si el proceso está en una llamada del núcleo (por ejemplo, haciendo E / S) cuando se envía SIGKILL?
gidds
9
@gidds O bien la E / S se cancelará para ejecutar el SIGKILL, o el SIGKILL se retrasará hasta que se complete la E / S. Esta es la diferencia entre los estados de suspensión 'S' y 'D' en ps: 'S' es para E / S en espera que el núcleo puede cancelar para entregar una señal, y 'D' para aquellos que no puede.
zwol
66
No es del todo exacto decir que la programación deja de darle tiempo al proceso de la CPU. El lado del núcleo del manejo de la señal aún se ejecuta mediante ese proceso, pero el proceso solo ejecutará el código del núcleo, por lo que tiene razón cuando dice que el programa nunca recibe la señal. El proceso ejecutará el código del núcleo responsable de la mayor parte de la limpieza de los recursos (archivos abiertos, memoria virtual, etc.). Los últimos pasos de este código de limpieza son cambiar el estado del proceso a zombie e invocar el programador. Entonces nunca más se programará.
kasperd
44
@gidds Hay al menos cuatro estados diferentes en los que puede estar el proceso. Puede estar ejecutando el código del núcleo en este momento o puede estar inactivo en uno de los tres estados diferentes de inactividad. Los estados de suspensión pueden ser interrumpibles, no interrumpibles o no interrumpibles, excepto para señales mortales. Si está en un sueño ininterrumpido, permanecerá dormido todo el tiempo que lo necesite y solo una vez que se despierte tendrá la oportunidad de morir. Si estaba en uno de los otros dos estados de suspensión, se despertará inmediatamente y se programará tan pronto como haya una CPU disponible para ello.
kasperd
2
@gidds Lo que suceda a continuación depende del código del núcleo que estaba ejecutando. Independientemente de si ya se estaba ejecutando o si primero tuvo que despertarse y luego podría comenzar a ejecutar el código del kernel en el que se encontraba en ese momento, se le permitirá continuar. Y ese código del kernel es responsable de notar que el proceso ha recibido instrucciones de morir y actuar en consecuencia. La mayoría de las veces, la forma correcta de lidiar con eso en el código del kernel es devolver un error de cualquier función que esté ejecutando. Una vez que la pila de llamadas del núcleo se ha desenrollado, el código de manejo de la señal puede hacerse cargo justo antes de volver al modo de usuario.
kasperd