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.