Señales en Unix
Una señal (signal, sigaction) es una
notificación a un proceso que un evento ocurrió. Muchas veces a las señales se
les conoce como interrupciones software porque ocurren por requerimiento de
usuario o programador. Usualmente las señales son asincrónicas, lo que
significa que un proceso no sabe con anticipación que un evento ocurrirá, pero
también pueden ser generadas sincrónicamente mediante un error en la
aplicación, es el caso de SIGFPE y SIGSEGV. Las señales pueden usarse para
comunicación entre usuario y proceso, para terminar o cancelar la ejecución de
un proceso, o entre procesos o bien entre sistema y proceso, ejecución de
instrucciones ilegales, etc.
Las señales son mensajes enviados por el
sistema operativo al proceso en ejecución. También puede verse como una forma
de atender eventos, es decir, permiten
interrumpir la ejecución de un proceso para atender la ocurrencia de un evento.
Un manejador de evento es el proceso que permite ejecutar el evento que
interrumpe, es decir, atender al evento. Normalmente se usa un manejador de
evento defecto que atiende eventos. Por ejemplo, en Unix, cuando se presiona
ctrl. C se envía una señal de interrupción al proceso en ejecución, resultando
en que el proceso se termina abruptamente.
Algunas de las señales especificadas en el
SO son las siguientes:
SIGHUP 1 /* hangup */ |
SIGINT 2 /* interrupt */ |
SIGQUIT 3 /* quit */ |
SIGILL 4 /* illegal instruction */ |
SIGABRT 6 /* used by abort */ |
SIGKILL 9 /* hard kill */ |
SIGALRM 14 /* alarm clock */ |
|
SIGCONT 19 /* continue a stopped process */ |
|
SIGCHLD 20 /* to parent on child stop or exit */ |
|
Las señales son
enumeradas desde el 0 al 31.
Enviando señales
Hay dos llamadas a sistema comunes para
enviar señales
int kill(int pid, int signal): proceso que ejecuta kill envía una señal a proceso especificado con pid.
Si pid = 0 señal es enviada a todos los procesos, excepto los procesos de
sistema
Si valor de retorno == 0 llamado es
exitoso sino error retorna en errno
int raise(int sig) envía señal sig a proceso en ejecución. Es similar a kill(getpid(), sig)
Utilitario kill pid termina proceso con
pid indicado. Si proceso no maneja señal proceso es terminado. Sólo procesos
con ciertos privilegios pueden ignorar la señal de kill.
Sólo procesos de un mismo usuario pueden
enviar y recibir mensajes
SIGKILL no puede ser ignorada y siempre
termina proceso.
Manejando señales
Usando llamadas a sistema signal() o
sigaction(). La primera se considera deprecada y es más seguro usar
sigaction(). Desde el punto de vista de programación ambas son muy similares.
Un proceso puede especificar un manejador
de señales para ser invocado cuando se recibe una señal. Cuando un manejador es
invocado para recibir una señal, se dice que atiende la señal. Un proceso puede
realizar las siguientes acciones cuando recibe la señal:
-
Proceso
puede realizar acción por defecto
-
Proceso
puede bloquear la señal (algunas pueden ignorarse)
-
Proceso
puede atender señal con un manejador
Manejadores usualmente se ejecutan en el stack
del proceso, lo cual implica que el manejador retorna al punto en que la
ejecución fue interrumpida.
Usando llamado a sistema signal()
Para atender una señal con la función
mi_manejador se usa
signal(SIGXXX, mi_manejador); donde SIGXXX indica la señal a recibir y a
atender en la función mi_manejador
Usando llamada a sistema sigaction
Este llamado a sistema utiliza estructuras
de datos para proporcionar el manejador de la señal que atenderá el evento como
para almacenar la información a la atención de la señal actualmente seteado.
Campos más utilizados en la estructura de
datos
sa_handler : indica el manejador de señal
sa_flags : una serie de valores,
incluyendo la posibilidad de permitir recibir señales dentro del manejador de
la señal
Declarar estructura sigaction
struct sigaction miatencion;
Setear miatencion;
miatencion.sa_handler = mi_manejador
Habilitar la recepción de señal para ser atendida según mistruc
sigaction(SIGXXX, &miatencion,
&atencionanterior);
si no se desea salvar la información acerca
de la atención anterior, usar NULL en su lugar.