Práctica 1 - Universidad Autónoma de Madrid

Anuncio
Sistemas Operativos I
Grupos
Lunes
Martes
Miércoles
Viernes
Realización
22 de Febrero, 1, 8, 15 de Marzo
23 de Febrero, 2, 9 y 16 de Marzo
24 de Febrero, 3, 10 y 17 de Marzo
19 y 26 de Febrero, 5 y 12 de Marzo
Práctica 1: Procesos y señales
Entrega/Evaluación
22 de Marzo
23 de Marzo
24 de Marzo
19 de Marzo (Entrega electrónica)
Teoría
Procesos
Los procesos tienen un tiempo de vida definido creándose mediante una llamada a fork o vfork.
Finalizan mediante un exit o un return en el main o cuando reciben una señal de terminación. A su vez
los procesos hijos creados pueden crear nuevos hijos o ejecutar otros programas mediante llamadas a
las funciones de la familia exec.
Todos los procesos tienen un proceso padre y pueden ser padres de varios procesos hijos. Esto
forma una estructura jerárquica en forma de árbol siendo el proceso init el tronco. Si un proceso
termina antes que sus hijos estos pasan a ser hijos de dicho proceso. Para diferenciar unos procesos de
otros dentro de este árbol se asigna a cada proceso un identificador único llamado identificador de
proceso, PID. Además el sistema maneja la llamada process table que consiste en un array de
estructuras tipo proc que contienen la información sobre los procesos que hay en el sistema, aunque no
estén en CPU.
Los procesos en System V R2 pueden estar en los siguientes estados:
•inicial (idle): El proceso está siendo creado pero todavía no está listo para ejecución.
•listo (runnable, ready to run) y en espera (blocked, asleep): El proceso está listo para
ser ejecutado. Puede estar en la memoria principal o en el intercambio (swapped).
•ejecución modo usuario (user running)
•ejecución modo kernel (kernel running)
•zombie: El proceso ha terminado pero su proceso padre no ha hecho wait(). Por esto el
proceso permanece en tabla de procesos y para el sistema el proceso sigue existiendo.
•parada (a partir de 4.2BSD): El proceso está parado. Esto se debe a que el proceso ha
recibido alguna señal de parada. Para salir de este estado debe recibir la señal de
continuación (SIGCONT).
En esta primera práctica de Sistemas Operativos I vamos a familiarizarnos con el uso de la
función de creación de procesos fork, de espera de hijos wait y de obtención de los pid de proceso con
getpid y del proceso padre con getppid.
Es necesario, por tanto, leer las páginas del manual de dichas funciones antes de empezar
los ejercicios.
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 1
Sistemas Operativos I
Práctica 1: Procesos y señales
Señales
Las señales son usadas por el kernel para notificar a los procesos de sucesos asíncronos. Por
ejemplo, si se pulsa Ctrl-C el kernel envía SIGINT. Además los procesos pueden enviarse señales
mediante la función kill.
Se responde a las señales al volver a modo usuario. Está respuesta puede ser terminar el
proceso, ignorar la señal o realizar una acción definida por el usuario. En cualquier caso esta acción no
se realiza de manera inmediata. El kernel pone un bit en la estructura proc del proceso indicando que la
señal ha llegado y si el proceso está en una espera interruptible lo saca de esta. En este caso la llamada
al sistema devolverá -1 y errno será EINTR.
En esta segunda parte vamos a familiarizarnos con el uso de las funciones de envío y captura de
señales kill y signal, así como de las funciones de espera pause y sigsuspend.
Es necesario, por tanto, leer las páginas del manual de dichas funciones antes de empezar
los ejercicios.
Ejercicios de procesos
1. Implementa un programa en C que use fork para crear el siguiente árbol de procesos. Ten
en cuenta que no es necesario generar ningún tipo de representación gráfica, más allá de
una frase indicando cuándo se ha creado un proceso, su pid y el pid de su padre. Observa
también que cada nodo es un proceso, y que el PID mostrado es únicamente orientativo.
¿Por qué crees que algunos nodos aparecen repetidos en el diagrama? (3 puntos)
1978
1978
fork
fork
1ª generación (21 = 2)
1979
fork
1978
1980
1979
1981
2
2ª generación (2 = 4)
2. ¿El orden de la salida al ejecutar el programa 1 es siempre el mismo? Justifica tu
respuesta. (1 punto)
3. Modifica el programa anterior, escribiendo un programa2.c que en lugar de generar 4
procesos, genere 32 procesos. Justifica la modificación realizada al código. (2 puntos)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 2
Sistemas Operativos I
Práctica 1: Procesos y señales
Escribe el siguiente código y guárdalo como programa3.c
// programa3.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char *argv [], char *env [])
{
int i, a=1;
}
for (i = 0; i < 10; i++)
{
switch (fork ())
{
case 0: a=3; printf(“a=
%d\n”,a); break;
}
printf(“a=%d\n”,a);
}
exit (0);
4. ¿Por qué puede fallar fork? ¿hay alguna forma de controlar el error de fork? Modifica el
código de programa3.c para controlarlo. (2 puntos)
5. ¿Qué otro problema tiene el código del programa3.c? Soluciónalo escribiendo el código
correcto de programa3.c como programa4.c (2 puntos)
6. ¿Cuánto vale la variable a para el código padre del programa4.c? ¿y el para el hijo? ¿por
qué no valen lo mismo? ¿en algún momento valen lo mismo? (1 punto)
7. Modifica el código de programa4.c como un nuevo programa5.c en el que el hijo devuelve
el valor de la variable a para que el printf que hace el padre muestre el mismo valor que el
printf que hace el proceso hijo. (2 puntos)
8. Explica las macros de wait en un ejemplo de programa padre (programa6.c) que cree un
proceso, y lo espere con wait, ¿cómo afecta a wait el uso de las macros? (2 puntos)
9. Modifica programa6.c como programa7.c para que en lugar de usar wait, espere al proceso
hijo usando waitpid. ¿Qué diferencias encuentras entre el uso de wait/waitpid? (2 puntos)
10. Escribe el código de un programa8.c que reserve en el proceso padre memoria dinámica
para una cadena de 20 caracteres de longitud y un proceso hijo. Si en el proceso hijo se
pide al usuario que introduzca un nombre para guardar en la cadena. ¿El proceso padre
tiene acceso a ese valor? ¿qué ocurre si el usuario no teclea nada? ¿dónde hay que liberar
la memoria reservada y por qué? (5 puntos)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 3
Sistemas Operativos I
Práctica 1: Procesos y señales
Ejercicios de señales
Escribe el siguiente código y guárdalo como programa9.c
// programa9.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void (*signal (int sig, void (*func)(int))) (int);
void captura (int sennal)
{
printf ("Capturada la señal %d\n", sennal);
fflush (NULL);
return;
}
int main (int argc, char *argv [], char *env [])
{
if (signal (SIGINT, captura) == SIG_ERR)
{
puts ("Error en la captura");
exit (1);
}
while (1);
exit (0);
}
11. Ejecuta el programa9.c, ¿la llamada a signal supone que se ejecute la función captura?
¿cuándo aparece el printf en pantalla? ¿por qué no aparece antes? (1 punto)
12. ¿Qué ocurre por defecto cuando un programa recibe una señal y no la tiene capturada?
Demuestra tu respuesta modificando el código de programa9.c y guardando el código
resultante como programa10.c (2 puntos)
13. Escribe el código de un programa11.c que ignore la pulsación de Ctrl+C en el teclado.
¿Cómo podrías demostrar que realmente la señal ha sido ignorada? (2 puntos)
14. ¿Todas las señales tienen asociada una semántica previa? Si no es así, pon un ejemplo en
un programa12.c de algún tipo de señal definida por el usuario (2 puntos)
15. Escribe el código de un programa13.c que intente capturar SIGKILL, y que escriba en
la función manejadora “He conseguido capturar SIGKILL”. ¿Por qué nunca sale por
pantalla “He conseguido capturar SIGKILL”? (3 puntos)
16. ¿Por qué se permite el uso de variables globales para compartir datos entre la función
manejadora y el resto del programa que tiene capturada una señal? (1 punto)
17. ¿Qué diferencia hay entre usar pause o sigsuspend? Demuestra tu respuesta con dos
ejemplos de código (programa14.c y programa15.c) (2 puntos)
18. Escribe un programa16.c que capture todas las señales capturables. (2 puntos)
19. Mientras se ejecuta el código de la función manejadora del programa16.c asociada a
SIGUSR1, envíale SIGUSR2 desde otra terminal, ¿qué sucede? ¿por qué? (1 punto)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 4
Sistemas Operativos I
Práctica 1: Procesos y señales
20. Escribe el código de un programa17.c que establezca una alarma inicial de 20 segundos
en los que el programa debe mostrar por pantalla una secuencia numérica creciente
separada por comas. Cuando salte la alarma, la última línea mostrada en la pantalla debe
ser: “Estos son los números que me ha dado tiempo a contar en 20 segundos”. (5 puntos)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 5
Sistemas Operativos I
Práctica 1: Procesos y señales
Ejercicio Final de la Práctica 1
Escribe el código de un programa18.c que consista en un sistema básico de c a l c u l o d e
n ú m e r o s p r i m o s . En particular, se pide que el programa consista en un bucle que:
1. Pide al usuario dos números enteros (de los que se tomará únicamente su valor absoluto).
Por ejemplo: 4 y 13.
2. Crea tres procesos hijos:
- Un hijo se encarga de calcular todos los primos entre ambos números. En este caso 5, 7, 11,
13 y mostrarlos por pantalla.
- Otro hijo decidirá si el número menor de los dos es primo e
informará mediante exit al padre.
- Otro hijo decidirá si el número mayor es primo e informará al padre
mediante el exit.
Só lo el proceso hijo e n c a rg a do d e l cá l c u lo d e lo s p r i mo s mostrará su resultado
por pantalla. L o s d e m á s procesos hijos deben enviar el resultado de su operación al
proceso padre en el retorno de exit.
3. El proceso padre debe realizar una espera no activa para recoger los resultados de los
procesos hijos y los debe mostrar por pantalla respetando el siguiente orde:
- Primero la lista con los números primos: 5, 7, 11, 13
- despues el resultado sobre el número menor: El número 4 no es primo
- y por último el mensaje del número mayor: En número 13 es primo.
- Si se produjese cualquier error durante el proceso se infomaría al usuario por
pantalla .
El programa debe terminar en cualquier momento cuando el usuario pulse Ctrl+C, liberando
todos los recursos solicitados y sin dejar procesos zombie. También debe terminar si el
usuario tarda más de 1 minuto en introducir los valores a y b.
Para evitar que cada hijo recalcule los primos será solo uno de ellos el que lo haga e informe a
los demás. Para ello, una vez calculados los número primos, enviará una señal a cada uno de
los otros hijos para que estos la procesen e informen en consecuencia al padre de si su número
es primo o no. Para que este mecanismo de comunicación funcione es imprescindible
controlar el orden en que se lanzan los hijos y la sincronización entre ellos. Todas las esperas
han de ser no activas y, si es posible, no bloqueantes. (20 puntos)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 6
Sistemas Operativos I
Práctica 1: Procesos y señales
Ejemplo de Ejecución del Ejercicio Final
En cursiva se indica los valores introducidos por el usuario.
Introduce el valor del primer operando: 3
Introduce el valor del segundo operando: 15
La lista es: 3, 5, 7, 11, 13
El número 3 es primo
El número 15 no es primo
Introduce el valor del primer operando: -2
Introduce el valor del segundo operando: 4
La lista es: 2, 3
El número -2 no es primo
El número 4 no es primo
Recibido Ctrl-C. Fin del programa.
Criterios de evaluación
1. Todos los ejercicios son obligatorios. La puntuación se obtiene aplicando una regla de tres
directa, en la que 63 puntos equivalen a obtener un 10 en esta práctica.
2. Aquellos ejercicios que no contienen una respuesta con código, se evaluarán atendiendo a
la explicación realizada por el alumno/a. Para que el razonamiento sea considerado válido
debe ser suficientemente detallado y se puede apoyar en documentación externa. En ningún
caso, se considerará una respuesta válida una captura de pantalla sin explicación, o un código
sin explicación.
3. Los ejercicios que solicitan la realización de un código, deben ser también explicados, tanto
a nivel de comentarios en el propio código (que se debe entregar junto con la memoria, inserto
en los ejercicios o en apéndices), como en texto como respuesta al ejercicio. Esto es,
especialmente relevante en el caso del ejercicio final que debe ir acompañado de una
descripción textual del diseño realizado y la solución propuesta en el código.
4. No se tendrá en cuenta código que no compila. Recibiendo una fuerte penalización
programas que no realizan una correcta liberación de los recursos solicitados al Sistema
Operativo (por ej. dejar procesos zombie), o que no tienen un correcto control de errores (con
especial interés en el control de errores de las llamadas del sistema operativo tratadas en esta
práctica).
5. Por último, se valorará la correcta aplicación de los principios de la programación
estructurada (esto es, organizar el código en funciones en la medida de lo posible, separar las
definiciones y estructuras en un archivo .h, no usar “números mágicos”, etc.)
© Escuela Politécnica Superior
Universidad Autónoma de Madrid 7
Descargar