c signals posix

c - man kill



¿Cuál es la diferencia entre sigaction y signal? (7)

Desde la página de manual signal(3) :

DESCRIPCIÓN

This signal() facility is a simplified interface to the more general sigaction(2) facility.

Ambos invocan la misma instalación subyacente. Es de suponer que no debes manipular la respuesta con una sola señal con ambos, pero mezclarlos no debería hacer que se rompa nada ...

Estaba a punto de agregar un controlador de señal adicional a una aplicación que tenemos aquí y me di cuenta de que el autor había usado sigaction para configurar los otros manejadores de señales. Iba a usar la señal. Para seguir la convención, debería usar sigaction, pero si estaba escribiendo desde cero, ¿cuál debería elegir?


Para mí, esta línea de abajo fue suficiente para decidir:

La función sigaction () proporciona un mecanismo más completo y confiable para controlar las señales; las nuevas aplicaciones deberían usar sigaction () en lugar de signal ()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

Ya sea que esté comenzando desde cero o modificando un programa anterior, sigaction debería ser la opción correcta.


Son interfaces diferentes para las instalaciones de señal del sistema operativo. Uno debería preferir usar sigaction para señalar si es posible, ya que la señal () tiene un comportamiento definido por la implementación (a menudo propenso a la raza) y se comporta de manera diferente en Windows, OS X, Linux y otros sistemas UNIX.

Vea esta nota de seguridad para más detalles.


También sugiero usar sigaction () sobre la señal () y me gustaría agregar un punto más. sigaction () le da más opciones como pid del proceso que murió (es posible usar la estructura siginfo_t).


Usaría signal () ya que es más portátil, al menos en teoría. Votaré a cualquier comentarista que pueda proponer un sistema moderno que no tenga una capa de compatibilidad POSIX y admita la señal ().

Citando de la documentación de GLIBC :

Es posible usar las funciones de señal y sigacción dentro de un solo programa, pero hay que tener cuidado porque pueden interactuar de maneras un poco extrañas.

La función sigaction especifica más información que la función de señal, por lo que el valor de retorno de la señal no puede expresar el rango completo de posibilidades de sigacción. Por lo tanto, si usa la señal para guardar y luego restablecer una acción, es posible que no pueda restablecer correctamente un controlador establecido con sigaction.

Para evitar problemas como resultado, siempre use sigaction para guardar y restaurar un controlador si su programa usa sigaction en absoluto. Dado que sigaction es más general, puede guardar y restablecer correctamente cualquier acción, independientemente de si se estableció originalmente con signal o sigaction.

En algunos sistemas si establece una acción con señal y luego la examina con sigaction, la dirección del manejador que obtenga puede no ser la misma que la especificada con la señal. Puede que ni siquiera sea adecuado para usar como un argumento de acción con señal. Pero puede confiar en usarlo como argumento para sigaction. Este problema nunca ocurre en el sistema GNU.

Entonces, es mejor que uses uno u otro de los mecanismos consistentemente dentro de un solo programa.

Portabilidad Nota: la función de señal básica es una característica de ISO C, mientras que sigaction es parte del estándar POSIX.1. Si le preocupa la portabilidad a sistemas que no son POSIX, entonces debe usar la función de señal en su lugar.

Copyright (C) 1996-2008 Free Software Foundation, Inc.

Se concede permiso para copiar, distribuir y / o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.2 o cualquier versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes, sin Textos de Cubierta Frontal, y sin Textos de Cubierta Trasera. Se incluye una copia de la licencia en la sección titulada "Licencia de documentación libre de GNU".


la señal () es estándar C, sigaction () no.

Si puede usar cualquiera (es decir, está en un sistema POSIX), entonces use sigaction (); no se especifica si signal () restablece el controlador, lo que significa que para ser portátil debe volver a llamar a signal () dentro del controlador. Lo que es peor es que hay una carrera: si obtiene dos señales en sucesión rápida, y la segunda se entrega antes de reinstalar el controlador, tendrá la acción predeterminada, que probablemente será para matar su proceso. sigaction () , por otro lado, garantiza el uso de semántica de señal "confiable". No necesita volver a instalar el controlador, ya que nunca se restablecerá. Con SA_RESTART, también puede hacer que algunas llamadas al sistema se reinicien automáticamente (para que no tenga que verificar manualmente si hay EINTR). sigaction () tiene más opciones y es confiable, por lo que se recomienda su uso.

Psst ... no le digas a nadie que te dije esto, pero POSIX actualmente tiene una función bsd_signal () que actúa como signal () pero le da semántica a BSD, lo que significa que es confiable. Su uso principal es para portar aplicaciones antiguas que asumieron señales confiables, y POSIX no recomienda su uso.


Use sigaction() menos que tenga razones muy convincentes para no hacerlo.

La interfaz signal() tiene antigüedad (y por lo tanto disponibilidad) a su favor, y está definida en el estándar C. Sin embargo, tiene una serie de características indeseables que sigaction() evita, a menos que utilice los indicadores explícitamente agregados a sigaction() para permitirle simular fielmente el comportamiento de la signal() .

  1. La función de signal() no impide (necesariamente) que lleguen otras señales mientras se está ejecutando el controlador actual; sigaction() puede bloquear otras señales hasta que regrese el manejador actual.
  2. La función de signal() (normalmente) restablece la acción de la señal a SIG_DFL (predeterminado) para casi todas las señales. Esto significa que el manejador de signal() debe reinstalarse a sí mismo como su primera acción. También abre una ventana de vulnerabilidad entre el momento en que se detecta la señal y el manejador se reinstala, durante el cual si llega una segunda instancia de la señal, se produce el comportamiento predeterminado (generalmente final, a veces con prejuicio, también conocido como volcado del núcleo).
  3. El comportamiento exacto de la signal() varía entre los sistemas, y los estándares permiten esas variaciones.

En general, estas son buenas razones para usar sigaction() lugar de signal() . Sin embargo, la interfaz de sigaction() es innegablemente más complicada.

Cualquiera que sea el que uses, no te sientas tentado por las interfaces de señal alternativas como sighold() , sigignore() , sigpause() y sigrelse() . Son nominalmente alternativas a sigaction() , pero están apenas estandarizados y están presentes en POSIX para compatibilidad con versiones anteriores más que para usos serios. Tenga en cuenta que el estándar POSIX dice que su comportamiento en programas de subprocesos múltiples no está definido.

Los programas y señales de subprocesos múltiples son otra historia complicada. AFAIK, tanto signal() como sigaction() son correctos en aplicaciones de subprocesos múltiples.

Cornstalks observes :

La página man de Linux para signal() dice:

Los efectos de la signal() en un proceso de subprocesos múltiples no están especificados.

Por lo tanto, creo que sigaction() es el único que se puede usar de forma segura en un proceso de subprocesos múltiples.

Eso es interesante. La página del manual de Linux es más restrictiva que POSIX en este caso. POSIX especifica para la signal() :

Si el proceso es de subprocesos múltiples o si el proceso es de subproceso único y se ejecuta un controlador de señal que no sea el resultado de:

  • El proceso llama a abort() , raise() , kill() , pthread_kill() o sigqueue() para generar una señal que no está bloqueada
  • Una señal pendiente se desbloquea y se entrega antes de que la llamada que desbloqueó vuelva

el comportamiento no está definido si el manejador de señal se refiere a cualquier objeto que no sea errno con duración de almacenamiento estático diferente a la asignación de un valor a un objeto declarado como volatile sig_atomic_t , o si el manejador de señal llama a cualquier función definida en este estándar que no sea una de las funciones enumeradas en Conceptos de la señal .

Por lo tanto, POSIX especifica claramente el comportamiento de la signal() en una aplicación de subprocesos múltiples.

Sin embargo, sigaction() es preferible en prácticamente todas las circunstancias, y el código multihilo portátil debe usar sigaction() menos que haya una razón abrumadora por la que no pueda (como "solo use funciones definidas por el estándar C" - y sí , El código C11 puede ser multiproceso). Que es básicamente lo que dice el párrafo inicial de esta respuesta.