You are on page 1of 7

UNAN-Leon

Sistemas Operativos

Practica No 3
Seales
Contenido

Introduccin
Envo de una seal a otros procesos
Tratamiento de una seal
SIGALARM para crear temporizadores en nuestros programas
Ejemplo del uso de Seales entre procesos padre e hijo
Introduccin
En muchas situaciones los programas deben de estar preparados para tratar situaciones inesperadas o impredecibles,
como:
error en operacin en punto flotante,
aviso de un reloj de alarma,
la muerte de un proceso hijo,
solicitud de terminacin por parte del usuario (Control-C),
solicitud de suspensin por parte del usuario (Control-Z),
etc.
Cuando una de estas situaciones se produce, el kernel enva una seal al proceso correspondiente. Adems, cualquier
proceso puede enviar una seal a otro proceso, si tiene permiso. En System V hay definidas 19 seales, mientras que
BSD define 11 seales ms. Cuando un proceso recibe una seal puede tratarla de tres formas diferentes:

Ignorar la seal, con lo cual es inmune a la misma.


Invocar a una rutina de tratamiento por defecto. Esta rutina la posee el kernel.
Invocar a una rutina propia para tratar la seal.
La rutina de tratamiento por defecto de una seal realiza una de las siguientes acciones:
Termina el proceso y genera un fichero core, que contiene un volcado de memoria del contexto del proceso
(dump).
Termina el proceso sin generar un fichero core (quit).
Ignora la seal (ignore).
Suspende el proceso (suspend).
Reanuda la ejecucin del proceso.

Envo de seal a otros procesos:

kill()
int kill ( int pid,int sig ) ;
- kill() enva la seal con valor sig al proceso cuyo PID es pid.
- La seal se enva de forma satisfactoria si el proceso que enva y el que recibe son del mismo usuario, o bien si el
proceso que enva es del superusuario.
- kill() funciona de forma diferente dependiendo del valor de pid:

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos
Si pid > 0 la seal se enva al proceso cuyo PID es pid.
Si pid = 0 la seal se enva a todos los procesos que pertenecen al mismo grupo del proceso
Si pid = -1 la seal se enva a todos procesos cuyo UID real es igual al UID efectivo del proceso que la enva. Si el
proceso que la enva tiene UID efectivo de superusuario, la seal es enviada a todos los procesos, excepto al proceso 0
(swapper) y 1 (init).
Si pid < -1 la seal es enviada a todos los procesos cuyo ID de grupo coincide con el valor absoluto de pid.

Para mostrar las seales que nos proporciona nuestro ncleo y su identificativo numrico asociado, usaremos
el siguiente comando:
~$ kill -l
1)
5)
9)
13)
18)
22)
26)
30)
34)
38)
42)
46)
50)
54)
58)
62)

SIGHUP
SIGTRAP
SIGKILL
SIGPIPE
SIGCONT
SIGTTOU
SIGVTALRM
SIGPWR
SIGRTMIN+2
SIGRTMIN+6
SIGRTMIN+10
SIGRTMIN+14
SIGRTMAX-13
SIGRTMAX-9
SIGRTMAX-5
SIGRTMAX-1

2)
6)
10)
14)
19)
23)
27)
31)
35)
39)
43)
47)
51)
55)
59)
63)

SIGINT
SIGABRT
SIGUSR1
SIGALRM
SIGSTOP
SIGURG
SIGPROF
SIGSYS
SIGRTMIN+3
SIGRTMIN+7
SIGRTMIN+11
SIGRTMIN+15
SIGRTMAX-12
SIGRTMAX-8
SIGRTMAX-4
SIGRTMAX

3)
7)
11)
15)
20)
24)
28)
32)
36)
40)
44)
48)
52)
56)
60)

SIGQUIT
SIGBUS
SIGSEGV
SIGTERM
SIGTSTP
SIGXCPU
SIGWINCH
SIGRTMIN
SIGRTMIN+4
SIGRTMIN+8
SIGRTMIN+12
SIGRTMAX-15
SIGRTMAX-11
SIGRTMAX-7
SIGRTMAX-3

4)
8)
12)
17)
21)
25)
29)
33)
37)
41)
45)
49)
53)
57)
61)

SIGILL
SIGFPE
SIGUSR2
SIGCHLD
SIGTTIN
SIGXFSZ
SIGIO
SIGRTMIN+1
SIGRTMIN+5
SIGRTMIN+9
SIGRTMIN+13
SIGRTMAX-14
SIGRTMAX-10
SIGRTMAX-6
SIGRTMAX-2

Algunas seales importantes <signal.h>:


SIGTERM = Finalizacin controlada. Se enva para indicarle a un proceso que debe acabar su ejecucin. Puede ser
ignorada.
SIGKILL = Finalizacin abrupta. No se puede ignorar
SIGINT = Interrupcin. Se enva cuando se pulsa la tecla de interrupcin (Ctrl+C). Por defecto, se interrumpe el
programa.
SIGCLD = Terminacin de algn proceso hijo. Se enva al proceso padre. Ignorada por defecto
SIGCHLD = Cuando un proceso termina o para, el proceso enva esta seal a su padre.

Seales disponibles para el programador:


SIGUSR1 y SIGUSR2: Su significado es el que quiera definir el programador en su aplicacin.
Ejemplo envo de una seal a un proceso hijo mediante el uso de kill:
Programa que crea un proceso hijo que imprime cada segundo su pid. El proceso padre duerme 10 segundos y luego
mandar una seal al hijo para que termine.
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
main()
{
int pid;
if ((pid = fork()) = = 0)
{
while(1){

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos
printf(HIJO. PID = %d\n,getpid());
sleep(1);
}
}
sleep(10);
printf( PADRE. Terminacion del Proceso %d \n, pid);
kill (pid, SIGTERM);
exit(0);
}

Tratamiento de una seal


Para tratar una seal se utiliza la funcin: signal().
Cuando un proceso recibe una seal puede tratarla de tres formas diferentes:

Ignorar la seal.
Invocar a una rutina de tratamiento por defecto. Esta rutina la posee el kernel.
Invocar a una rutina creada por el usuario para tratar la seal.

#include <signal.h>
void (*signal (int sig, void (*accin) ())) ();
- signal() permite a un proceso especificar la accin a tomar cuando reciba una seal en particular.
- sig especifica el nmero de la seal a tratar.
- accin puede tomar:
SIG_DFL: indica que se use el manejador por defecto del kernel.
SIG_IGN: indica que la seal se debe ignorar.
Cuando queremos que un proceso espere a que le llegue una seal, usaremos la funcin pause(). Esta funcin
provoca que el proceso (o thread) en cuestin duerma hasta que le llegue una seal. Para capturar esa seal, el
proceso deber haber establecido un tratamiento de la misma con la funcin signal(). La funcin pause() no recibe
ningn parmetro y retorna 1 cuando la llamada a la funcin que captura la seal ha terminado.
#include <unistd.h>
int pause(void);

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos

Ejemplo: Ignorar la seal.


#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
main()
{
int pid;
pid=fork();
if (pid==0)
{
/*codigo hijo*/
signal(SIGTERM,SIG_IGN);
while(1)
{
printf("soy el hijo\n");
sleep(1);
}
}
else
{
sleep(5);
printf("\n Proceso Padre..\n");
kill(pid,SIGTERM);
printf("\n FIN DEL PADRE \n");
}
}

Ejemplo: Invocar a una rutina de


tratamiento por defecto.
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
main()
{
int pid;
pid=fork();
if (pid==0)
{
/*codigo hijo*/
signal(SIGTERM,SIG_DFL);
while(1)
{
printf("soy el hijo\n");
sleep(1);
}
}
else
{
sleep(5);
printf("\n Proceso Padre...\n");
kill(pid,SIGTERM);
printf("\n FIN DEL PADRE \n");
}
}

Ejemplo: Invocar a una rutina propia


para tratar la seal
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
void mifuncion()
{
printf("\n SOY LA RUTINA DE
TRATAMIENTO POR EL
USUARIO\n");
exit(0);
}
main()
{
int pid;
pid=fork();
if (pid==0)
{
/*codigo hijo*/
signal(SIGTERM,mifuncion);
while(1)
{
printf(" soy el hijo\n");
sleep(1);
}
}
else
{
sleep(10);
printf(" Fin del Padre\n");
kill(pid,SIGTERM);
exit(0);
}
}

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos
Ejemplo (Captura la seal cuyo Id asociado esta entre 1 y 64 ):
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void trapper(int);
main()
{
int i;
for(i=1;i<=64;i++)
signal(i, trapper);
printf("Proceso \n");
pause();
printf("Continuando...\n");
return 0;
}
void trapper(int sig)
{
signal(sig, trapper);
printf("Recibida la seal: %d\n", sig);
}
Explicacin del programa:
Inicialmente declaramos una funcin que va a recibir un entero como parmetro y se encargar de capturar una
seal (trapper() ). Seguidamente capturamos todas las seales de 1 a 64 haciendo 64 llamadas a signal(), pasando como
primer parmetro el nmero de la seal (i) y como segundo parmetro la funcin que se har cargo de dicha seal
(trapper). Seguidamente el programa espera a que le llegue una seal con la funcin pause(). El programa esperar
indefinidamente la llegada de esa seal, y cuando le enviemos una (por ejemplo, pulsando Control+C), la funcin
encargada de gestionarla (trapper() ) ser invocada. Lo primero que hace trapper() es volver a enlazar la seal en
cuestin a la funcin encargada de gestionarla, es decir, ella misma, y luego saca por la salida estndar la seal
recibida. Al terminal la ejecucin de trapper(), se vuelve al punto donde estbamos ( pause() ) y se continua:

SIGALARM para crear temporizadores en nuestros programas


Una utilizacin bastante potente de las seales es el uso de SIGALARM para crear temporizadores en nuestros
programas. Con la funcin alarm() lo que conseguimos es que nuestro proceso se enve a s mismo una seal
SIGALARM en el nmero de segundos que especifiquemos. El prototipo de alarm() es el siguiente:
unsigned int alarm(unsigned int seconds);
En su nico parmetro indicamos el nmero de segundos que queremos esperar desde la llamada a alarm() para recibir
la seal SIGALARM.
La llamada a la funcin alarm() generar una seal SIG_ALARM hacia el mismo proceso que la invoca.
El valor devuelto es el nmero de segundos que quedaban en la anterior alarma antes de fijar esta nueva alarma. Esto es
importante: slo disponemos de un temporizador para usar con alarm(), por lo que si llamamos seguidamente otra vez a
alarm(), la alarma inicial ser sobrescrita por la nueva.

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos
Ejemplo de su utilizacin:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void trapper(int);
main()
{

()

int i;
signal(14, trapper);
printf("Identificativo de proceso: %d\n", getpid() );
alarm(5);
pause();
alarm(3);
pause();
for(;;)
{
alarm(1);
pause();
}
return 0;

}
void trapper(int sig)
{
signal(sig, trapper);
printf("RIIIIIIIIING!\n");
}
Explicacin del programa:
Este programa es bastante similar al que hemos diseado antes para capturar seales, slo que ahora en lugar
de capturarlas todas, capturar nicamente la 14, SIGALARM. Cuando reciba una seal SIGALARM, sacar
RIIIIIIIIING por pantalla. El cuerpo del programa indica que se fijar una alarma de 5 segundos y luego se esperar
hasta recibir una seal, luego la alarma se fijar a los 3 segundos y se volver a esperar, y finalmente se entrar en un
bucle en el que se fije una alarma de 1 segundo todo el rato. El resultado es que se mostrar un mensaje RIIIIIIIIING
a los 5 segundos, luego a los 3 segundos y despus cada segundo:

Ejemplo del uso de Seales entre procesos padre e hijo


En este ejemplo, el hijo enva varias seales SIGUSR1 a su padre y al final termina por matarlo, envindole la seal
SIGKILL:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void trapper(int sig)
{
signal(sig, trapper);
printf("SIGUSR1\n");
}

Msc. Rina Arauz

UNAN-Leon
Sistemas Operativos
main()
{
pid_t padre, hijo;
padre = getpid();
signal( SIGUSR1, trapper );
if ( (hijo=fork()) == 0 )
{ /* hijo */
sleep(1);
kill(padre, SIGUSR1);
sleep(1);
kill(padre, SIGUSR1);
sleep(1);
kill( padre, SIGUSR1);
sleep(1);
kill(padre, SIGKILL);
exit(0);
}
else
{ /* padre */
for (;;);
}
return 0;
}
EJERCICIOS
1. Realice un programa que cree un proceso hijo, deber entrar en un bucle infinito y esperar. El proceso padre
deber matar a su proceso hijo despus de 10 segundos. Y aparecer por pantalla el PID del padre, el PID del
hijo y un mensaje indicando la muerte del hijo y la finalizacin del padre.
2. Cree un proceso que nos informe de la cantidad de veces que se pulsa (CTRL+C) en un periodo de 25
segundos.
3. Realice un programa que mediante el uso de la seal SIGALARM realice lo siguiente. Un programa espera por
una cadena introducida por teclado. Si pasados 20 segundos esta accin no se realiza, el proceso deber
decirTermino el tiempo de espera FIN.
4. Implementar un programa que cree un proceso hijo, el cual deber imprimir su PID, y PPID. El padre deber
esperar su finalizacin y capturar la seal de muerte del proceso hijo e imprimir el mensaje MI HIJO HA
MUERTO.

Msc. Rina Arauz