A menudo me desconcierta que, aunque he trabajado profesionalmente con computadoras durante varias décadas y Linux durante una década, en realidad trato la mayor parte de la funcionalidad del sistema operativo como una caja negra, no muy diferente a la magia.
Hoy pensé en el kill
comando, y aunque lo uso varias veces al día (tanto en su "normal" como en su -9
sabor) debo admitir que no tengo ni idea de cómo funciona detrás de escena.
Desde mi punto de vista, si un proceso en ejecución está "colgado", llamo kill
a su PID, y de repente ya no se está ejecutando. ¡Magia!
¿Qué pasa realmente allí? Las páginas de manual hablan de "señales" pero seguramente eso es solo una abstracción. Enviar kill -9
a un proceso no requiere la cooperación del proceso (como manejar una señal), simplemente lo elimina.
- ¿Cómo impide Linux que el proceso continúe ocupando tiempo de CPU?
- ¿Se elimina de la programación?
- ¿Desconecta el proceso de sus identificadores de archivo abiertos?
- ¿Cómo se libera el proceso 'memoria virtual?
- ¿Hay algo así como una tabla global en la memoria, donde Linux mantiene referencias a todos los recursos ocupados por un proceso, y cuando "mato" un proceso, Linux simplemente pasa por esa tabla y libera los recursos uno por uno?
¡Realmente me gustaría saber todo eso!
fuente
kill -9
referencia .Respuestas:
Supone que, debido a que algunas señales pueden captarse e ignorarse, todas implican cooperación. Pero según
man 2 signal
"las señales SIGKILL y SIGSTOP no pueden ser captadas o ignoradas". SIGTERM puede ser atrapado, por lo que el simplekill
no siempre es efectivo, generalmente esto significa que algo en el controlador del proceso ha salido mal. 1Si un proceso no (o no puede) definir un controlador para una señal dada, el kernel realiza una acción predeterminada. En el caso de SIGTERM y SIGKILL, esto es para terminar el proceso (a menos que su PID sea 1; el núcleo no terminará
init
) 2, lo que significa que sus identificadores de archivo están cerrados, su memoria regresó al grupo de sistemas, su padre recibe SIGCHILD, su huérfano los hijos son heredados por init, etc., como si hubiera llamadoexit
(verman 2 exit
). El proceso ya no existe, a menos que termine como un zombi, en cuyo caso todavía aparece en la tabla de proceso del núcleo con alguna información; eso sucede cuando su padre nowait
y lidiar con esta información correctamente. Sin embargo, los procesos zombie ya no tienen memoria asignada y, por lo tanto, no pueden continuar ejecutándose.Creo que eso es lo suficientemente preciso. Se realiza un seguimiento de la memoria física por página (una página generalmente equivale a un fragmento de 4 KB) y esas páginas se toman y se devuelven a un grupo global. Es un poco más complicado porque algunas páginas liberadas se almacenan en caché en caso de que los datos que contienen se vuelvan a requerir (es decir, datos que se leyeron de un archivo aún existente).
Claro, todas las señales son una abstracción. Son conceptuales, al igual que los "procesos". Estoy jugando semántica un poco, pero si te refieres a SIGKILL es cualitativamente diferente de SIGTERM, entonces sí y no. Sí en el sentido de que no se puede atrapar, pero no en el sentido de que ambas son señales. Por analogía, una manzana no es una naranja, pero las manzanas y las naranjas son, según una definición preconcebida, ambas frutas. SIGKILL parece más abstracto ya que no puedes atraparlo, pero sigue siendo una señal. Aquí hay un ejemplo de manejo de SIGTERM, estoy seguro de que has visto esto antes:
Este proceso dormirá para siempre. Puede ejecutarlo en una terminal y enviarlo con SIGTERM
kill
. Escupe cosas como:1066 es mi UID. El PID será el del shell desde el cual
kill
se ejecuta, o el PID de kill si lo bifurcas (kill 25309 & echo $?
).Nuevamente, no tiene sentido establecer un controlador para SIGKILL porque no funcionará. 3 Si yo
kill -9 25309
el proceso terminará. Pero eso sigue siendo una señal; el kernel tiene la información sobre quién envió la señal , qué tipo de señal es, etc.1. Si no ha mirado la lista de posibles señales , vea
kill -l
.2. Otra excepción, como menciona Tim Post a continuación, se aplica a procesos en suspensión ininterrumpida . No se pueden despertar hasta que se resuelva el problema subyacente, por lo que TODAS las señales (incluida SIGKILL) se difieren por la duración. Sin embargo, un proceso no puede crear esa situación a propósito.
3. Esto no significa que usar
kill -9
es algo mejor que hacer en la práctica. Mi controlador de ejemplo es malo en el sentido de que no conduce aexit()
. El verdadero propósito de un controlador SIGTERM es darle al proceso la oportunidad de hacer cosas como limpiar archivos temporales y luego salir voluntariamente. Si lo usakill -9
, no tiene esta oportunidad, así que solo haga eso si la parte de "salir voluntariamente" parece haber fallado.fuente
-9
porque ese es el verdadero problema de cómo quién desea que este muera. ;)kill -9
ciertos procesos vinculados de E / S no funcionará, al menos no de inmediato.kill -9
no se puede detectar un proceso, un proceso que lo recibe no puede realizar ninguna limpieza (por ejemplo, eliminar archivos temporales, liberar memoria compartida, etc.) antes de que salga. Por lo tanto, usekill -9
(akakill -kill
) solo como último recurso. Comience con aykill -hup
/ okill -term
primero y luego úselokill -kill
como el golpe final.Cada proceso se ejecuta durante el tiempo programado y luego es interrumpido por el temporizador de hardware, para proporcionar su núcleo de CPU para otras tareas. Es por eso que es posible tener muchos más procesos que núcleos de CPU, o incluso ejecutar todo el sistema operativo con muchos procesos en una CPU de un solo núcleo.
Después de que se interrumpe el proceso, el control vuelve al código del núcleo. Ese código puede tomar la decisión de no reanudar la ejecución del proceso interrumpido, sin ninguna cooperación del lado del proceso. kill -9 puede terminar la ejecución en cualquier línea de su programa.
fuente
Aquí hay una descripción idealizada de cómo funciona matar un proceso. En la práctica, cualquier variante de Unix tendrá muchas complicaciones y optimizaciones adicionales.
El núcleo tiene una estructura de datos para cada proceso que almacena información sobre qué memoria está mapeando, qué hilos tiene y cuándo están programados, qué archivos tiene abiertos, etc. Si el núcleo decide matar un proceso, hace una nota en La estructura de datos del proceso (y tal vez en la estructura de datos de cada uno de los hilos) que el proceso debe ser eliminado.
Si uno de los subprocesos del proceso está actualmente programado en otra CPU, el núcleo podría desencadenar una interrupción en esa otra CPU para que ese subproceso deje de ejecutarse más rápidamente.
Cuando el planificador advierte que un hilo está en un proceso que debe ser eliminado, ya no lo programará.
Cuando ya no se programan ninguno de los subprocesos del proceso, el núcleo comienza a liberar los recursos del proceso (memoria, descriptores de archivo, ...). Cada vez que el núcleo libera un recurso, verifica si su propietario todavía tiene recursos activos. Una vez que el proceso no tiene más recursos en vivo (mapeo de memoria, descriptor de archivo abierto, ...), la estructura de datos para el proceso en sí se puede liberar y la entrada correspondiente se puede eliminar de la tabla de procesos.
Algunos recursos pueden liberarse inmediatamente (por ejemplo, desasignar memoria que no está siendo utilizada por una operación de E / S). Otros recursos deben esperar, por ejemplo, los datos que describen una operación de E / S no se pueden liberar mientras la operación de E / S está en progreso (mientras un DMA en progreso, la memoria a la que está accediendo está en uso y la cancelación del DMA requiere en contacto con el periférico). El conductor de dicho recurso recibe una notificación y puede intentar acelerar la cancelación; una vez que la operación ya no esté en progreso, el controlador completará la liberación de ese recurso.
(La entrada en la tabla de proceso es en realidad un recurso que pertenece al proceso padre, que se libera cuando el proceso muere y el padre reconoce el evento ).
fuente