Actualmente tengo problemas con mis usuarios quejándose de la finalización de mi aplicación. Bajo algunas condiciones (aparentemente arbitrarias) y entornos de escritorio, la aplicación no finaliza y la configuración no se guarda al reiniciar. Pregunté en los canales de irc correspondientes y la mayoría de las veces me dicen que maneje las señales correctamente. Conozco SIGINT para Ctrl-C en la terminal y SIGTERM para la terminación "normal". Pero me dijeron que SIGHUP también es importante. Entonces mi pregunta es:
¿Qué señales tengo que manejar para crear una aplicación que se comporte bien?
Respuesta1
https://en.wikipedia.org/wiki/Unix_signal
tiene una lista de señales estándar y sus acciones predeterminadas. Cualquier proceso con privilegios suficientes siempre puede enviarle cualquier señal, pero los procesos (o usted, a través de los procesos) no deberían hacer esto.
Solo debe kill
y esperar que sus procesos se editen kill
conTÉRMINOy un montón de señales que puede generar su entorno (el shell, el controlador del terminal), a menos que sepa que el objetivo maneja la señal especial que desea enviar.
Puede ordenar las señales básicas por sus acciones.
Las señales de coredumping
ABRT TRAP SYS BUS FPE ILL SEGV XFSZ XCPU QUIT
son generados por usted (TRAP, ABRT, SYS) utilizando algunas funciones especializadas o por entrar en estados de error grave (BUS, FPE, ILL, SEGV).
QUIT
es generado por un usuario en una terminal que desea un volcado de núcleo ( C+\
).
Es posible que desee mantenerlos en sus disposiciones predeterminadas.
Fuera deseñales de terminación:
HUP INT PIPE TERM ALRM POLL PROF USR1 USR2
deberías esperar
HUP INT PIPE TERM
de su entorno en diversas circunstancias:
HUP -- when the terminal hungs up or you become a stopped orphaned process
INT -- when the user at the terminal interrupts you with C-c
PIPE -- when a PIPE or socket you write into closes, e.g. by
exiting before you finished writing to it
(`yourprogram | (exit)` will give you a `PIPE`
if yourprogram attempts to write to its STDOUT)
TERM -- when a process ends you a normal termination request
Debería recibir el resto de las señales de terminación sólo si lo configura usted mismo.
MATARyDETENERno puedes hacer nada al respecto.
Es posible que desees interceptar el terminal generado.señales de parada:
TTIN -- you read from the terminal and you're a backgrounded process
TTOU -- you write the terminal when you're a backgrounded process
and the terminal is set to put you to sleep when you do
TSTP -- you're being put to sleep with `C-Z`
pero en el peor de los casos, estos simplemente detendrán su proceso, sin corromper su estado.
A menos que sepa que necesita manejar CHLD
, CONT
o URG
no lo hace.
TL;DR:
Básicamente, creo que HUP, INT, PIPE y TERM deben manejarse (o ignorarse) si normalmente desea realizar una limpieza previa a la salida. El resto se puede dejar en paz, a menos que su programa utilice esas señales, o a menos que necesite absolutamente alguna limpieza en todas las circunstancias.
En el último caso, puede bloquear en blanco todas las señales no controladas, pero tenga en cuenta que las máscaras de bloqueo de señales se heredan a través de bifurcaciones y llamadas ejecutivas e ignoran o bloquean señales como ILL, si surgieron de la ejecución de su proceso y no se le enviaron. por kill o sigqueue le dará un comportamiento indefinido.
Si desea obtener más información, explore las páginas de manual y los estándares. Las señales son un tema bastante importante en Unix y manejarlas puede resultar muy complicado.
Respuesta2
Si sigue ese camino, probablemente terminará ignorando un buen número de señales, simplemente porque una de ellas está finalizando su programa. Como sugiere sablynx en un comentario, el mejor curso de acción sería analizar estas señales y comprender de dónde provienen. Después de todo, puede haber una buena razón para que su programa sea eliminado.
Dicho esto, puedes echar un vistazo asignals(7)
para obtener una lista de señales que pueden provocar la terminación del proceso:
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1 y SIGUSR2.
Si su aplicación pasa algún tiempo conectada a una terminal, su manejo SIGINT
es una buena idea ( Ctrl+ Ces bastante famoso después de todo). SIGTERM
También es una buena idea porque sigue siendo la señal de terminación básica y es utilizada por el núcleo (por ejemplo, al apagar el sistema). SIGQUIT
Es probablemente la versión "más dura" de las dos anteriores, ya que provoca un volcado del núcleo. Cuando reciba ese, probablemente debería esperarse que su programa falle de inmediato. Al recibir cualquiera de los demás, se esperaría que su programa "limpiara su desorden y se fuera" (guarde la configuración, finalice correctamente).
SIGILL
, SIGFPE
y SIGSEGV
son SIGPIPE
señales relacionadas con el mal comportamiento del programa.Fallo de segmentaciónEsta es probablemente la situación más recurrente, pero al final, todos estos casos pueden tratarse como errores y no creo que captar la señal sea la mejor manera de recuperarse de estas situaciones.
- La mayoría de las veces, los compiladores no permiten que
SIGILL
esto suceda tan fácilmente (más aquí) así que creo que puedes dejar eso a un lado. - Asegúrate de nunca dividir por cero y evitarás la mayoría de
SIGFPE
las s. Aparte de eso, sólo asegúrese de que su programa sea bueno en matemáticas y no se vuelva loco con los números. SIGSEGV
puede ser causado por varias cosas (acceso ilegal a la memoria, eliminación de barreras ilegales), y para eso sugeriría usarlogdb
para vigilar su programa mientras se ejecuta y rastrear la instrucción desagradable usandogdb
la pila.- Por último,
SIGPIPE
está relacionado principalmente con flujos de datos (lectura de archivos, conexiones,...). Si es probable que alguna de las secuencias de E/S de su programa finalice mientras se ejecuta, debe asegurarse de que su programa verifique sus descriptores antes de usarlos y maneje todos los eventos de E/S que ocurran en él (al usarselect
opoll
, por ejemplo).gdb
podría ser útil aquí también.
SIGABRT
, SIGALRM
y son básicamente señales de usuario SIGUSR1
. SIGUSR2
Si los estás recibiendo, es probable que realmente hayas hecho que eso suceda.
Esto nos deja con SIGHUP
y SIGKILL
, que es posible que no se detecten.
SIGHUP
ocurrirá, por ejemplo, si inicia el proceso desde una terminal y luego cierra esa terminal sin desconectar el proceso (disown
o usarnohup
). Si su programa se inicia desde la terminal y se ejecuta como un demonio, no olvide separarlo del shell, por ejemplo mediante una doble bifurcación. Esta señal particular es menos relevante si su programa puede iniciarse desde una GUI, o en el momento del arranque, donde es menos probable que el terminal de control esté "cerrado".SIGKILL
como sabes, es el todopoderoso de las señales. Es la forma que tiene el núcleo de decir "¡mierda!". Si estás recibiendo eso, entonces debes centrar tu atención en lo que sea que esté emitiendo la señal, en lugar de cómo manejarlo en tu programa.
Al final, analizar la señal y utilizar herramientas de depuración es probablemente el enfoque más sencillo para estos problemas. Si el kernel activa una señal cuando su programa se comporta mal, gdb
debería ayudarle a localizar el problema. En ese caso, olvídate de la señal y concéntrate en el error del que te habla.
Si la señal proviene del "exterior", encontrar el emisor probablemente sea el mejor curso de acción.(si realmente no puedes encontrarlo,rastreoelkill(2)
la llamada al sistema podría ser un buen último recurso). Luego podrás decidir si quieres ignorarlo ( SIG_IGN
), o tenerlo en cuenta. Silenciar el programa emisor también puede ser una buena alternativa...