¿Se puede ignorar (perder) la señal?

9

Tengo una aplicación que se comunica con los trabajadores a través de señales (particularmente SIGUSR1 / SIGUSR2 / SIGSTOP).

¿Puedo confiar en que pase lo que pase cada señal será entregada y procesada por el controlador?

¿Qué sucede si las señales se envían más rápido de lo que no es posible que la aplicación las maneje (por ejemplo, debido a la alta carga del host en este momento)?

KaP
fuente

Respuestas:

8

Aparte del problema de "demasiadas señales", las señales pueden ignorarse explícitamente. De man 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

Las señales también se pueden bloquear. De man 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

Los conjuntos secundarios de señales bloqueadas e ignoradas son heredadas por los procesos secundarios, por lo que puede ocurrir que el proceso principal de su aplicación ignore o bloquee una de estas señales.

¿Qué sucede cuando se entregan varias señales antes de que el proceso haya terminado de manejar las anteriores? Eso depende del sistema operativo. La página de signal(2)manual vinculada anteriormente lo discute:

  • El sistema V restablecería la disposición de la señal a la predeterminada. Peor aún, la entrega rápida de múltiples señales daría lugar a llamadas recursivas (?).
  • BSD bloquearía automáticamente la señal hasta que el controlador esté listo.
  • En Linux, esto depende de los indicadores de compilación establecidos para GNU libc, pero esperaría el comportamiento BSD.
muru
fuente
44
La página de manual de Linux para signal(2)sugiere enfáticamente que evite esta confusión al usar en su sigaction(2)lugar.
Nate Eldredge
7

No puede confiar en que se entregarán todas las señales enviadas. Por ejemplo, el kernel de Linux "fusiona" SIGCHLD si un proceso tarda mucho en manejar SIGCHLD desde un proceso hijo salido.

Para responder otra parte de su pregunta, las señales se "ponen en cola" dentro del núcleo si llegan varias señales diferentes en un intervalo demasiado corto.

Debe usar sigaction()para configurar el controlador de señal con el sa_sigactionmiembro de siginfo_t, estableciendo el sa_maskmiembro del siginfo_targumento con cuidado. Creo que esto significa enmascarar todas las señales "asíncronas" al menos. Según la página del manual para Linux sigaction(), también ocultará la señal que se está manejando. Creo que debería establecer el sa_flagsmiembro en SA_SIGINFO, pero no recuerdo por qué tengo esta superstición. Creo que esto le dará a su proceso un controlador de señal que se mantiene sin condiciones de carrera, y que no se ve interrumpido por la mayoría de las otras señales.

Escriba su función de controlador de señal con mucho, mucho cuidado. Básicamente, establezca una variable global para indicar que se atrapó una señal y haga que el resto del proceso se ocupe de la acción deseada para esa señal. Las señales se enmascararán por la menor cantidad de tiempo de esa manera.

Además, querrá probar su código de manejo de señal muy a fondo. Póngalo en un pequeño proceso de prueba y envíe tantas señales SIGUSR1 y SIGUSR2 como sea posible, tal vez desde 2 o 3 programas de envío de señales de propósito especial. Mezcle también algunas otras señales, después de que esté seguro de que su código puede manejar SIGUSR1 y SIGUSR2 de manera rápida y correcta. Prepárese para la depuración difícil.

Si usa Linux y solo Linux, puede pensar en usarlo signalfd()para crear un descriptor de archivo que pueda select()o sondear para recibir esas señales. El uso signalfd()podría facilitar la depuración.

Bruce Ediger
fuente
2
No solo se fusiona SIGCLD: todas las señales se fusionan potencialmente si se entregan antes de que puedan procesarse.
Gilles 'SO- deja de ser malvado'
¿Hay alguna medida de cuánto tiempo es "demasiado largo" para las señales SIGCHLD? Estoy experimentando este comportamiento en mi programa en este momento, y mi controlador de señal no tarda más de ~ 100 ms, creo.
xrisk
@Rishav: que yo sepa, no hay forma de averiguar qué es "demasiado tiempo". Esperaría que la carga general del sistema sea importante. Es decir, lo que otros procesos y el núcleo están haciendo afectaría "cuánto tiempo" entre las señales para que se unan. No es una respuesta útil, creo.
Bruce Ediger
6

Se garantiza que se entregará una señal, en el sentido de que si un proceso llama con éxito kill, entonces el objetivo recibirá la señal. Esto es asíncrono: el remitente no tiene forma de saber cuándo se recibe o procesa la señal. Sin embargo, esto no garantiza que se entregue la señal. El objetivo podría morir antes de poder procesar la señal. Si el objetivo ignora la señal en el momento en que se entrega, la señal no tendrá efecto. Si el objetivo recibe varias instancias del mismo número de señal antes de poder procesarlas, las señales pueden (y generalmente se combinan): si envía la misma señal dos veces a un proceso, no puede saber si el proceso recibirá la señal una o dos veces. Las señales están diseñadas principalmente para matar un proceso o como una forma de hacer que un proceso preste atención, no están diseñadas para la comunicación como tal.

Si necesita una entrega confiable, entonces necesita un mecanismo de comunicación diferente. Hay dos mecanismos principales de comunicación entre procesos: una tubería permite la comunicación unidireccional; un socket permite la comunicación bidireccional y múltiples conexiones al mismo servidor. Si necesita que el destino procese tantas notificaciones como lo envíe, envíe bytes a través de una tubería.

Gilles 'SO- deja de ser malvado'
fuente
44
¿Quería escribir "Se garantiza que se entregará una señal" ya que describió algunas de las formas en que la señal no se entregaría (es decir, el proceso murió antes de ser recibido o las señales se fusionaron)?
Johnny
2

El núcleo es libre de fusionar señales estándar si se entrega más de una mientras está bloqueado. Las señales en tiempo real, por otro lado, no tienen desventajas similares.

Desde la página del manual de la señal (7) :

Las señales en tiempo real se distinguen por lo siguiente:

  1. Se pueden poner en cola múltiples instancias de señales en tiempo real. Por el contrario, si se entregan varias instancias de una señal estándar mientras esa señal está actualmente bloqueada, solo una instancia se pone en cola.

Intente usar una señal con un número en el rango SIGRTMIN a SIGRTMAX.

Graham Rushton
fuente
Hay un límite para las señales en tiempo real, pero es bastante alto. Se eliminará una señal si el número de señales pendientes pendientes enviadas por el usuario supera RLIMIT_SIGPENDING. ulimit -imuestra este valor como 63432 en Ubuntu 18.04.
Bain