Introducción
Las señales son interupciones de
software.
Permiten el manejo de eventos asíncronos.
Conceptos
Cada señal tiene un nombre. Ellos
comienzan con SIG. Ej. SIGABRT
El archivo <
signal.h
> contiene la definición de todas las señales. La ubicación
definitiva de las señales depende del sistema operativo de su máquina.
Generalmente se puede llegar a él vía /usr/include/signal.h.
Numerosas condiciones pueden generar señales.
Entre ellas:
Presionando la tecla DELETE (también control-C)Hay tres cosas que un programa puede solicitar al kernel como acción cuando llegue una señal:
Excepción de hardware: División por cero, referencia de memoria invalida (SIGSEGV)
kill : existe como función y como comando. El procesador que envia debe pertenecer al mismo usuario del que recibe o ser superusuario.
Condiciones de software. Por ejemplo: SIGALRM generada por al alarma del reloj cuando expira. SIGPIPE: cuando se escribe en una "pipe" que ha terminado por el lado lector.
SIGALRM: generada cuando el timer asociado a la función alarm expira. También cuando el timer de intervalo es configurado (setitimer)Función signal
SIGCHLD: Cuando un proceso termina o para, el proceso envia esta señal a su padre. Por defecto esta señal es ignorada. Normalmente el proceso padre invoca la función wait para obtener el status de término del proceso hijo.
SIGCONT: es enviada para reanudar un proceso que ha sido parado (suspendido).
SIGINT: generada con DELETE o Control-C
SIGKILL: Permite terminar un proceso.
SIGTSTP: generada cuando presionamos Control-Z. Puede ser ignorada.
SIGSTOP: similar a SIGTSTP pero no puede ser ignorada o capturada.
SIGUSR1: Es una señal definida por el usuario para ser usada en programas de aplicación.
SIGUSR2: Otra como la anterior.
#include
<signal.h>
void (*signal
(int signo, void (*func) (int)))(int);
signo: es el nombre de la señal.
func: puede ser la constante SIG_IGN
para ignorar la señal, SIG_DFL para usar la acción por defecto,
o puede ser una función definida por el programa. Esta función
es conocida como el manejador de la señal (signal handler). El valor
retornado es un puntero al manejador previamente instalado para esa señal.
Este prototipo es equivalente
a:
typedef void Sigfunc(int);
Sigfunc * signal (int, Sigfunc *);
Ejemplo: uso de SIGUSR1 y SIGUSR2
Interrupción de
llamados al sistema
Ocurre cuando
la señal arriba cuando el proceso esta bloqueado en una llamado al
sistema "lento".
el llamado al sistema retorna un
error y el valor de errno es EINTR.
Típico
código para atender esta situación:
again:
if ( (n=read(fd, buff, BUFFSIZE)) < 0) {
if(errno == EINTR)
goto again;
/* manejo de otros errores */
}
Cuidado con llamar a funciones que
no son reentrantes!!!
Funciones kill y raise
kill envía
us señal a un proceso o a un grupo de procesos. raise permite enviar
señales al mismo proceso (hacia uno mismo).
#include <sys/types.h>
#include <signal.h>
int kill (pid_t
pid, int signo);
int raise(int signo);
Este último es como kill( getpid(), signo);
Funciones alarm y pause
La función
alarm permite especificar un timer que expire en un tiempo dado.
La función
pause suspemde al proceso llamador hasta que llegue una señal.
#include
<unistd.h>
unsigned int
alarm(unsigned int seconds);
En nuevas
versiones de sistema operativo también se puede usar
unsigned int
ualarm(unsigned int microseconds);
int pause(void); /* retorna -1 con errno en EINTR */
El control
del tiempo no es exacto por la incertidumbre del kernel, carga del sistema,
etc.
Hay sólo
una alarma por proceso!
La alarma se
puede cancelar con seconds=0 en el argumento. El valor retornado es lo que
falta para que el reloj expire.
Ejemplo 1 de uso de alarma: sleep() vía programa
.
Explicar por
qué este programa tiene los siguientes problemas: Qué pasa si
el llamador ya tiene la alarma configurada?. Que pasa si el programa tenía
otro manejador definido previamente? hay alguna carrera crítica?
Ejemplo 2 de uso de alarma: Llamado a read con time out .
Función sleep
sleep suspende
al proceso llamador por la una cantidad de segundos indicada o hasta que se
reciba una señal.
#include <unistd.h>
unsiged int sleep
(unsigned int seconds);
Hoy también
tenemos disponible
unsiged int usleep(unsigned
int microseconds);
Retorna 0
ó el tiempo que no se durmió.