jueves, 27 de octubre de 2016

2.2 Señales entre procesos

Control de Señales

Cuando una señal se envía a un proceso, que no esté preparado para recibirla, el proceso se mata.

SIGNAL(señal, &funcion)
int señal;
int (*función)(); función a realizar cuando se recibe una señal.

Esta llamada se utiliza para indicar que se está preparado para recibir algún tipo de señal y suministrar la dirección del procedimiento manejador de la señal.

Después del SIGNAL, si se recibe una señal por ejemplo SIGINT (pulsar la tecla DEL), se efectúa:

1)     El estado del proceso se guarda en su propia pila.
2)     Se ejecuta el manejador de la señal.



SIGRETURN (&contexto)

Es llamado por el manejador que atiende la señal cuando termina. Recupera el estado del proceso interrumpido desde la pila y lo continúa.

Los tipos de señales son:

1.       SIGHUP El modem ha detectado línea telefónica colgada
2.       SIGINT Interrupción de teclado, la tecla DEL ha sido pulsada
3.       SIGQUIT Señal Quit (desde el teclado CTRL \)
4.       SIGILL Instrucción ilegal
5.       SIGTRAP Traza de los traps (excepciones)
6.       SIGABRT Abortar un programa
7.       SIGBUS Error en el Bus
8.       SIGFPE Excepción por rebosamiento de coma flotante
9.       SIGKILL Matar un proceso
10.    SIGUSR1 El usuario define la señal # 1
11.    SIGSEGV Violación de segmentación
12.    SIGUSR2 El usuario define la señal # 2
13.    SIGPIPE Escritura en pipe sin lectores
14.    SIGALRM Alarma
15.    SIGTERM Software genera una señal de terminación
16.    SIGSTKFLT Fallo en el stack
17.    SIGCHLD Cambia el estado del hijo, terminado o bloqueado
18.    SIGCONT Si está bloqueado continuar
19.    SIGSTOP Señal de paro
20.    SIGTSTP Paro del teclado
21.    SIGTTIN Proceso en segundo plano quiere leer, lectura terminal
22.    SIGTTOU Proceso en segundo plano quiere escribir, escritura terminal
23.    SIGURG Condición urgente
24.    SIGXCPU Excedido el límite de la CPU
25.    SIGXFSZ Excedido el limite del tamaño de un fichero
26.    SIGVTALRM Alarma del reloj virtual
27.    SIGPROF Historial del reloj
28.    SIGWINCH Cambia el tamaño de la ventana
29.    SIGIO Ahora es posible la entrada salida
30.    SIGPWR Fallo en la alimentación
31.    SIGSYS Llamada al sistema erronea
32.    SIGRTMIN Primera señal en tiempo real
33.    SIGRTMAX Última señal en tiempo real

Después de recibir una señal, en principio es necesario volver a permitir recibir otra señal con otro SIGNAL, ya que si no, puede recibirse una señal y matar el proceso (acción por defecto), existe un parámetro para que se vuelva a cargar la función.

Existen dos funciones predefinidas que el usuario puede utilizar:

·      SIG_IGN, para que las señales se ignoren (excepto SIGKILL).
·      SIG_DFL, para ejecutar la acción por defecto de matar al proceso.

Ejemplo: Supongamos que lanzamos un comando en modo tanda: command &

Es indeseable que la señal DEL, del teclado pueda afectar a ese proceso, así, el Shell después de ejecutar el FORK, pero antes del EXEC deberá hacer

·      signal (SIGNIT, SIG_IGN);
·      signal (SIGQUIT, SIG_IGN);

Que inhiben las señales DEL, y QUIT (CTRL\).

SIGACTION (sig, *act, *oact)

Es una nueva versión de signal, examina, pone o modifica los atributos de una señal.

Sig es un entero que indica la señal.
*act es una estructura que contiene los atributos y manejador de la señal
*oact es la estructura que recibe los atributos antes de la llamada.

ALARM (segundos)

Esta llamada se utiliza para interrumpir un proceso al cabo de un cierto tiempo, su parámetro especifica el tiempo en segundos, después del cual el núcleo envía la señal SIGALRM al proceso.

Un proceso solo puede tener una alarma pendiente, para resetear una alarma, basta hacer una llamada de alarma con parámetro cero.

PAUSE (segundos)

Esta llamada le dice al S.O. que suspenda al proceso, hasta que se reciba una señal.

SIGPROCMASK(how, &set, &old)

Esta señal permite bloquear un conjunto de señales mediante una mascara de bits que le envía al núcleo del sistema.

SIGPENDING(SET)

Obtiene el conjunto de señales bloqueadas.

SIGSUSPEND(sigmask)

Permite a un proceso establecer atómicamente el mapa de bits de las señales bloqueadas y suspenderse a sí mismo.




Control de Procesos

En este tópico parece no haber mucho que decir; existe una serie de herramientas para administrar los procesos, algunas de las cuales se valen de señales para cumplir con su objetivo.

Algunos de estos procesos son:

pid = fork() - crea un proceso hijo idéntico al proceso padre.
pid = waitpid(pid, &statloc, opts) - espera a que un hijo determinado termine y coge su condición de salida.
s = wait(&status) - espera a que un proceso hijo termine y coge su condición de salida devuelve el pid del hijo que termina, llamada antigua.
s = execve (name, argv, envp) - sustituye la imagen en memoria de un proceso.
exit(status) - pone fin a la ejecución del proceso y devuelve  la condición de salida.
size = brk (addr) - fija el tamaño del segmento de datos a (addr).
pid = getpid() - devuelve el id del proceso solicitante.
pid = getpgrp() - devuelve el id de grupo de procesos del proceso solicitante.
pid = setsid() - crea una nueva sesión y asigna el pid del invocador como identificador del grupo de procesos.
s = ptrace(req, pid, addr, data) - controla un proceso para depurar.

FORK()

Crea un nuevo proceso, exactamente igual  al proceso  original, incluyendo los descriptores de ficheros, registros,  ambiente, etc.


Una vez ejecutado el FORK, padre, e hijo se están ejecutando  simultáneamente, en un principio las variables tienen los mismos  valores, después, cambios en uno no afectan al otro.

La llamada FORK devuelve un valor después de ejecutarse,  este valor es:

 cero -> en el proceso hijo

pid (identificador del proceso hijo -> en el padre

Mediante este valor los procesos pueden saber cuál es el  padre y cuál es el hijo.


WAITPID

pid =  waitpid(pid, &statloc, opts) - espera a que un hijo determinado termine, devolviendo el pid del proceso que termina, y coge su condición de salida.

En mucho casos, el hijo creado por el FORK necesita lanzar  un proceso, distinto al del padre. Ejemplo:

El Shell, lee un comando, lanza un proceso hijo, y debe esperar hasta que el proceso hijo ejecute el  comando, posteriormente lee un  nuevo comando cuando el hijo termina.

Para esperar a que el hijo termine, el padre debe ejecutar  WAITPID.
Si el parámetro pid vale -1, el padre espera por el primer hijo que termina El segundo parámetro statloc es la dirección de una variable  (estado de salida) que es escrita por el proceso hijo para  indicar terminación normal o anormal.

EXEC.

s = execve (name, argv, envp) - sustituye la imagen en memoria de un proceso.
name - nombre del fichero que contiene el programa a ejecutar.

argv - vector de argumentos.
envp - vector ambiente

En el caso del Shell, el proceso hijo debe ejecutar el comando, esto lo hace mediante la llamada EXEC, la cual hace que la imagen del hijo, sea reemplazada por el fichero que hay en el primer parámetro de EXEC.

Ejemplo: Shell simplificado con FORK, WAITPID y EXEC.

While (TRUE){ /* bucle indefinido */
        read_command (command, parámetro); /* lee comando */
       if ( fork() != 0){ /* lanza un proceso hijo */
              waitpid(-1,&status,0); /* el padre espera a que hijo acabe */
      }else{
              execve(command, parámetros, 0); /* ejecuta el comando */
     }
};

EXIT().

Esta llamada la deben utilizar lo procesos cuando terminan.

Devuelve al padre un valor de estatus (0 a 255), que se carga en el byte menos significativo de la variable estatus de WAITPID, un cero es terminación normal, otro valor es error.

BRK(adr)

Esta llamada cambia el tamaño del segmento de datos de un programa. El parámetro adr que indica el nuevo tamaño en bytes del segmento de datos. Devuelve el tamaño actual del segmento de datos.

La rutina sbrk, en la librería, también cambia el tamaño del segmento de datos, su parámetro indica el número de bytes que aumenta (positivo) o disminuye (negativo) el segmento de datos.

GETPID


Devuelve el identificador del proceso (pid) que lo ejecuta. En un Fork, al padre se le devuelve el pid del hijo, mientras que al hijo se le devuelve un cero, si el hijo quiere saber su pid, deberá efectuar un GETPID.

0 comentarios:

Publicar un comentario