2011-12-06 32 views
13

En un sistema que ejecuta Linux 2.6.35+, mi programa crea muchos procesos secundarios y los supervisa. Si un proceso secundario muere, hago algunas tareas de limpieza y vuelvo a generar el proceso. Yo uso signalfd() para obtener la señal SIGCHLD en mi proceso. signalfd se usa de forma asincrónica usando libevent.Manejo de SIGCHLD múltiple

Al usar manejadores de señal para señales en tiempo no real, mientras el manejador de señal se está ejecutando para una señal particular, la ocurrencia adicional de la misma señal debe bloquearse para evitar entrar en manejadores recursivos. Si llegan varias señales en ese momento, kernel invoca el controlador solo una vez (cuando la señal está desbloqueada).

¿Es el mismo comportamiento al usar signalfd() también? Dado que el manejo basado en signalfd no tiene los problemas típicos asociados con la ejecución asincrónica de los manejadores de señal normales, estaba pensando en kernel queue todas las ocurrencias adicionales de SIGCHLD?

¿Alguien puede aclarar el comportamiento de Linux en este caso ...

Respuesta

17

En Linux, varios niños que terminan antes de leer un SIGCHLD con signalfd() serán comprimidos en un solo SIGCHLD. Esto significa que cuando se lee la señal SIGCHLD, usted tiene que limpiar después de todos los niños que han terminado:

// Do this after you've read() a SIGCHLD from the signalfd file descriptor: 
while (1) { 
    int status; 
    pid_t pid = waitpid(-1, &status, WNOHANG); 
    if (pid <= 0) { 
     break; 
    } 
    // something happened with child 'pid', do something about it... 
    // Details are in 'status', see waitpid() manpage 
} 

Debo señalar que he hecho visto este compresión de la señal cuando el niño dos procesa termina en el Mismo tiempo. Si solo hice un solo waitpid(), uno de los hijos que terminó no fue manejado; y el ciclo anterior lo arregló.

correspondiente documentación:

  • http://man7.org/linux/man-pages/man7/signal.7.html"Por el contrario, si se entregan varias instancias de una señal estándar, mientras que la señal está actualmente bloqueada, a continuación, sólo una instancia se pone en cola"
  • http://man7.org/linux/man-pages/man3/sigwait.3p.html"Si antes de la llamada a sigwait() hay múltiples instancias pendientes de un solo número de señal, está definido por la implementación si al regresar con éxito hay cualquier señal pendiente pendiente para ese número de señal ".
+0

Gracias .. par de preguntas ..
Digamos que hay muchos eventos en la cola de epoll que mi proceso aún no agota. En ese caso, ¿está usted diciendo que kernel pondrá en cola solo un evento de lectura para SIGCHLD en la señal transmitida incluso si mueren n procesos? Sobre usar el waitpid() en un bucle, el problema que tengo con este enfoque es que solo obtiene el estado de salida del proceso hijo, pero pierde otra información que obtendría de struct signalfd_siginfo cuando lee desde signalfd (o siginfo_t cuando usa sigaction). ¿Supongo que no hay forma de obtener eso? – Manohar

+0

@Santhosh, tenga en cuenta que epoll no pone en cola los eventos del descriptor de archivos en el sentido literal; más bien, solo informa el estado de los descriptores de archivos (legibilidad, capacidad de escritura). Entonces, cuando ocurren eventos en un descriptor de archivo que lo hace legible, no importa cuántos hay, epoll solo informará la legibilidad.Y la próxima vez que haga un epoll_wait(), hará exactamente lo mismo (excepto si usa epoll activado por flanco, pero aún así no informará el número de eventos). Sobre la estructura signalfd_siginfo, creo que tienes razón. Pero, ¿qué necesitarías de allí en caso de SIGCHLD de todos modos? –

+2

@Santhosh: también tenga en cuenta que signalfd() comprime las señales SIGCHLD, no epoll. Esto significa que no solo no obtendrá múltiples eventos de epoll, sino que obtendrá una sola señal SIGCHLD de read(); la estructura signalfd_siginfo de los otros se perderá para siempre. –

0

En realidad, la forma libre de problemas sería el waitfd funcionalmente que permitirá añadir un PID específico para sondear()/epoll(). Desafortunadamente, no fue aceptado en Linux hace años cuando se propuso.

+2

Realmente quise agréguelo como un comentario, no como una respuesta, lo siento. –