Manejo de señales con múltiples subprocesos en Linux

119

En Linux, ¿qué sucede cuando un programa (que posiblemente tiene varios subprocesos) recibe una señal, como SIGTERM o SIGHUP?

¿Qué hilo intercepta la señal? ¿Pueden varios subprocesos obtener la misma señal? ¿Existe un hilo especial dedicado enteramente al manejo de señales? Si no es así, ¿qué sucede dentro del hilo que debe manejar la señal? ¿Cómo se reanuda la ejecución después de que finaliza la rutina del controlador de señales?


fuente

Respuestas:

35

Esto tiene algunos matices, según la versión del kernel de Linux que esté utilizando.

Suponiendo 2.6 subprocesos posix, y si está hablando de que el sistema operativo envía SIGTERM o SIGHUP, la señal se envía al proceso, que es recibido y manejado por el subproceso raíz. Al usar subprocesos POSIX, también puede enviar SIGTERM a subprocesos individuales, pero sospecho que está preguntando qué sucede cuando el sistema operativo envía la señal al proceso.

En 2.6, SIGTERM hará que los subprocesos secundarios salgan "limpiamente", mientras que en 2.4, los subprocesos secundarios se dejaron en un estado indeterminado.

Alan
fuente
¿Y qué sucede dentro del hilo raíz cuando se recibe una señal? Digamos que escribí un manejador de señales personalizado para SIGUSR1, y ahora estoy enviando esa señal al proceso. El hilo raíz recibirá esa señal. Tal vez esté en medio de alguna función en ese momento. Que es lo que va a pasar?
1
si tiene una configuración de controlador, se tratará como una interrupción, el flujo del programa se detendrá y se ejecutará su controlador personalizado. Una vez ejecutado, el control volverá, asumiendo que no ha hecho nada para alterar el flujo normal (salida, etc.).
Alan
Tenga en cuenta que esto es específico de SIGUSR1, que IIRC no interrumpe las llamadas al sistema. Si intentó esto con SIGINT, por ejemplo, podría interrumpir la lectura de un flujo y, cuando regresara a la lectura, el flujo puede devolver un error de que se interrumpió.
Alan
10
Estoy un poco confundido acerca de lo que se entiende por "hilo raíz". ¿Significa esto que el controlador de SIGTERM siempre se ejecutará en el hilo principal, o puede ejecutarse en cualquier hilo?
Stephen Nutt
3
Esta respuesta , que establece que se elige un hilo arbitrario para manejar la señal, contradice su respuesta.
user202729
135

pthreads(7) describe que POSIX.1 requiere que todos los subprocesos de un proceso compartan atributos, incluidos:

  • disposiciones de señal

POSIX.1 también requiere que algunos atributos sean distintos para cada hilo, incluidos:

La complete_signalrutina del kernel de Linux tiene el siguiente bloque de código; los comentarios son bastante útiles:

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

Por lo tanto, se ve que usted está a cargo de donde se entregan las señales:

Si su proceso ha establecido la disposición de una señal en SIG_IGNo SIG_DFL, entonces la señal se ignora (o de forma predeterminada: kill, core o ignore) para todos los subprocesos.

Si su proceso ha establecido la disposición de una señal a una rutina de manejo específica, entonces puede controlar qué hilo recibirá las señales manipulando máscaras de señal de hilo específico usando pthread_sigmask(3). Puede nominar un hilo para gestionarlos todos, o crear un hilo por señal, o cualquier combinación de estas opciones para señales específicas, o puede confiar en el comportamiento predeterminado actual del kernel de Linux de entregar la señal al hilo principal.

Algunas señales, sin embargo, son especiales según la signal(7)página del manual:

Una señal puede ser generada (y por lo tanto pendiente) para un proceso como un todo (por ejemplo, cuando se envía usando kill (2) ) o para un hilo específico (por ejemplo, ciertas señales, como SIGSEGV y SIGFPE, generadas como consecuencia de la ejecución una instrucción específica en lenguaje de máquina está dirigida por subprocesos, al igual que las señales dirigidas a un subproceso específico usando pthread_kill (3) ). Se puede entregar una señal dirigida al proceso a cualquiera de los subprocesos que actualmente no tiene la señal bloqueada. Si más de uno de los hilos tiene la señal desbloqueada, entonces el núcleo elige un hilo arbitrario al cual enviar la señal.

sarnold
fuente