En general, para matar procesos generamos señales como SIGKILL
, SIGTSTP
etc.
Pero, ¿cómo se sabe quién ordenó esa señal en particular, quién la envió a un proceso en particular y, en general, cómo realizan sus operaciones las señales? ¿Cómo funcionan las señales internamente?
kill
signals
architecture
Varun Chhangani
fuente
fuente
Respuestas:
La vista de 50,000 pies es que:
El núcleo genera una señal internamente (por ejemplo,
SIGSEGV
cuando se accede a una dirección no válida, oSIGQUIT
cuando presiona Ctrl+ \), o mediante un programa que utiliza lakill
llamada al sistema (o varias relacionadas).Si es por una de las llamadas al sistema, entonces el núcleo confirma que el proceso de llamada tiene suficientes privilegios para enviar la señal. Si no, se devuelve un error (y la señal no sucede).
Si es una de dos señales especiales, el núcleo actúa incondicionalmente sobre ella, sin ninguna entrada del proceso de destino. Las dos señales especiales son SIGKILL y SIGSTOP. Todo lo siguiente sobre acciones predeterminadas, señales de bloqueo, etc., es irrelevante para estos dos.
A continuación, el núcleo descubre qué hacer con la señal:
Para cada proceso, hay una acción asociada con cada señal. Hay un montón de valores predeterminados, y los programas pueden establecer diferentes usando
sigaction
,signal
etc. Estos incluyen cosas como "ignorarlo completamente", "matar el proceso", "matar el proceso con un volcado de núcleo", "detener el proceso", etc.Los programas también pueden desactivar la entrega de señales ("bloqueadas"), señal por señal. Entonces la señal permanece pendiente hasta que se desbloquee.
Los programas pueden solicitar que, en lugar de que el kernel tome alguna acción, entregue la señal al proceso de forma síncrona (con
sigwait
, et. Al. Osignalfd
) o asíncronamente (interrumpiendo lo que sea que esté haciendo el proceso y llamando a una función específica).Hay un segundo conjunto de señales llamadas "señales en tiempo real", que no tienen un significado específico, y también permiten que se pongan en cola múltiples señales (las señales normales solo ponen en cola una de cada una cuando la señal está bloqueada). Estos se utilizan en programas de subprocesos múltiples para que los hilos se comuniquen entre sí. Varios se utilizan en la implementación de hilos POSIX de glibc, por ejemplo. También se pueden usar para comunicarse entre diferentes procesos (por ejemplo, podría usar varias señales en tiempo real para que un programa fooctl envíe un mensaje al demonio fooctl).
Para una vista que no sea de 50,000 pies, pruebe
man 7 signal
y también la documentación interna del kernel (o fuente).fuente
La implementación de la señal es muy compleja y es específica del núcleo. En otras palabras, diferentes núcleos implementarán señales de manera diferente. Una explicación simplificada es la siguiente:
La CPU, basada en un valor de registro especial, tiene una dirección en la memoria donde espera encontrar una "tabla de descriptores de interrupción" que en realidad es una tabla de vectores. Hay un vector para cada posible excepción, como la división por cero, o trap, como INT 3 (depuración). Cuando la CPU encuentra la excepción, guarda los indicadores y el puntero de instrucción actual en la pila y luego salta a la dirección especificada por el vector relevante. En Linux, este vector siempre apunta al núcleo, donde hay un controlador de excepciones. La CPU ya está lista y el kernel de Linux se hace cargo.
Tenga en cuenta que también puede activar una excepción del software. Por ejemplo, el usuario presiona CTRL- C, luego esta llamada va al kernel que llama a su propio controlador de excepciones. En general, hay diferentes formas de llegar al controlador, pero independientemente de lo mismo sucede: el contexto se guarda en la pila y se accede al controlador de excepciones del núcleo.
El controlador de excepciones luego decide qué hilo debe recibir la señal. Si ocurre algo como la división por cero, entonces es fácil: el hilo que causó la excepción recibe la señal, pero para otros tipos de señales, la decisión puede ser muy compleja y, en algunos casos inusuales, un hilo más o menos aleatorio podría Recibe la señal.
Para enviar la señal, lo que hace el núcleo es establecer primero un valor que indique el tipo de señal,
SIGHUP
o lo que sea. Esto es solo un número entero. Cada proceso tiene un área de memoria de "señal pendiente" donde se almacena este valor. Luego, el núcleo crea una estructura de datos con la información de la señal. Esta estructura incluye una "disposición" de señal que puede ser predeterminada, ignorada o manejada. El núcleo luego llama a su propia funcióndo_signal()
. La siguiente fase comienza.do_signal()
primero decide si se va a manejar la señal. Por ejemplo, si es un asesinato ,do_signal()
simplemente mata el proceso, final de la historia. De lo contrario, mira la disposición. Si la disposición es predeterminada,do_signal()
maneja la señal de acuerdo con una política predeterminada que depende de la señal. Si la disposición es manejar, significa que hay una función en el programa de usuario que está diseñada para manejar la señal en cuestión y el puntero a esta función estará en la estructura de datos mencionada anteriormente. En este caso, do_signal () llama a otra función del núcleo,handle_signal()
, que luego pasa por el proceso de volver al modo de usuario y llamar a esta función. Los detalles de este traspaso son extremadamente complejos. Este código en su programa generalmente se vincula automáticamente a su programa cuando usa las funciones ensignal.h
.Al examinar adecuadamente el valor de la señal pendiente, el núcleo puede determinar si el proceso está manejando todas las señales, y tomará las medidas apropiadas si no lo está, lo que podría poner el proceso en suspensión o matarlo u otra acción, dependiendo de la señal.
fuente
Aunque esta pregunta ha sido respondida, permítanme publicar un flujo detallado de eventos en el kernel de Linux.
Esto se copia completamente de las publicaciones de Linux: Señales de Linux: partes internas en el blog "Publicaciones de Linux" en sklinuxblog.blogspot.in.
Programa Signal User Space C
Comencemos escribiendo un programa simple de espacio de usuario de señal C:
Este código asigna un nuevo controlador para la señal SIGINT. SIGINT puede enviarse al proceso en ejecución utilizando la combinación de teclas Ctrl+ C. Cuando se presiona Ctrl+ C, la señal asíncrona SIGINT se envía a la tarea. También es equivalente a enviar el
kill -INT <pid>
comando en otra terminal.Si haces un
kill -l
(que es una minúsculaL
, que significa "lista"), conocerás las diversas señales que se pueden enviar a un proceso en ejecución.También se puede usar la siguiente combinación de teclas para enviar señales particulares:
Si compila y ejecuta el programa C anterior, obtendrá el siguiente resultado:
Incluso con Ctrl+ Co
kill -2 <pid>
el proceso no terminará. En su lugar, ejecutará el controlador de señal y volverá.Cómo se envía la señal al proceso
Si vemos el funcionamiento interno de la señal que se envía a un proceso y ponemos Jprobe con dump_stack en
__send_signal
función, veremos el siguiente seguimiento de llamada:Entonces, la función principal para enviar la señal es la siguiente:
Ahora todo está configurado y se realizan los cambios necesarios en
task_struct
el proceso.Manejo de señal
La señal es verificada / manejada por un proceso cuando regresa de la llamada al sistema o si se realiza la devolución de la interrupción. La devolución de la llamada del sistema está presente en el archivo
entry_64.S
.Se llama a la función int_signal function desde la
entry_64.S
cual se llama a la funcióndo_notify_resume()
.Verifiquemos la función
do_notify_resume()
. Esta función verifica si tenemos laTIF_SIGPENDING
bandera establecida entask_struct
:SISTEMA llamadas y señales
Llamadas de sistema "lentas", por ejemplo, bloqueo de lectura / escritura, poner procesos en estado de espera:
TASK_INTERRUPTIBLE
oTASK_UNINTERRUPTIBLE
.Una tarea en estado
TASK_INTERRUPTIBLE
cambiará alTASK_RUNNING
estado mediante una señal.TASK_RUNNING
significa que se puede programar un proceso.Si se ejecuta, su controlador de señal se ejecutará antes de completar la llamada al sistema "lenta". El
syscall
no se completa por defecto.Si se
SA_RESTART
establece el indicador,syscall
se reinicia después de que finaliza el controlador de señal.Referencias
fuente
kill
comando, que es un shell incorporado). (2c) Si bien los puntos y comas después del cierre}
de una función no son, estrictamente hablando, errores, son innecesarios y muy poco ortodoxos. (3) Incluso si todo fuera correcto, no sería una muy buena respuesta a la pregunta. (3a) La pregunta, aunque algo poco clara, parece centrarse en cómo los actores (usuarios y procesos) inician (es decir, envían ) señales. ... (Continúa)