Introducció als Sistemes Operatius Facultat d`Informàtica de

Anuncio
Pregunta 2. Pifo (2.5 punts)
Introducció als Sistemes Operatius
Facultat d'Informàtica de Barcelona - UPC
Data: 26 de Gener de 2004
Estamos interesados en hacer una nueva función de librería llamada pifo. Su prototipo es el siguiente:
Duració: 3 hores
int pifo (int pids[2]);
ATENCIÓ: Les preguntes 1, 2 i 3 es contestaran en fulls separats, i les 4, 5, 6 i 7 contesteu-les en el mateix full.
Notes: Les notes es publicaran el dimarts 3 de febrer de 2004 a les 16:00 al web de la FIB
Revisió: Es podran veure els examens i demanar revisió el dimecres 4 o dijous 5. El lloc i hora exactes es publicaran amb
les notes el dimarts 3. Estigueu atents.
Notes revisades: les notes revisades es publicaran el divendres 6 de febrer a les 15:00 al web de la FIB
Pregunta 1. La barberia es reforma (1,5 punts)
Una barberia té una sala d’espera amb N cadires, i una sala amb la cadira de barber. Si no hi ha clients per atendre,
el barber es fa la migdiada. Si entra un client a la barberia, i totes les cadires estan ocupades, marxa de la barberia.
Si el barber està ocupat, però hi ha cadires lliures, llavors s’espera a una de les cadires. Si el barber està adormit,
el client desperta al barber. Implementarem les rutines del barber i els clients tot fent servir semàfors.
Et donem l’estructura del programa. Cal definir els semàfors necessaris, fer la seva inicialització, i incloure les
crides necessaries per a evitar problemes d’exclussió mutua. Cal seguir l’esquema proposat:
int seients_lliures;
/*Variable numero de seients lliures a la sala d’espera */
int barber_adormit;
/*Indica si el barber esta adormit o no */
sem_t...;
/* Aqui cal declarar els semafors que es considerin necessaris
*/
/*Rutina per inicialitzar els semafors i les variables necessaries */
void inicialitzacio ()
{...}
void barber ()
{
while (1)
{
/* Mirar si hi ha clients a la sala d’espera */
if (seients_lliures == N)
{
barber_adormit = TRUE;
/* Aqui cal esperar que arribi un client */
}
/* Ara un client de la sala d’espera pasa a la cadira del barber */
seients_lliures++;
/*Ara ja tenim un client a la cadira del barber, cal treballar */
afeitar;
}
}
void client ()
{
/* Arriba un nou client a la barberia */
if (seients_lliures != 0)
{
if (barber_adormit)
{
/* Cal despertar-lo */
barber_adormit = FALSE;
}
seients_lliures--;
/* Esperem el nostre torn a la sala d’espera, fins que el barber ens avisi*/
/* Ara passem a la cadira del barber */
afeitat;
}
/* el client surt de la barberia */
}
Esta función crea dos procesos y los comunica entre ellos con una pipe.
Por tanto, cuando acaba la función, el proceso creado que lee de la pipe tiene su canal de entrada estándar
redireccionado a la pipe, y el proceso creado que escribe en la pipe, tiene su canal de salida estándar
redireccionado a esta pipe.
En el vector "pids", dependiendo del proceso, la función tiene que devolver lo siguiente:
• si el proceso es el padre, el vector "pids" contiene los pids de los dos hijos {pid del que lee, pid del que escribe}
• si el proceso es el hijo que lee de la pipe, el vector "pids" contiene {0, -1}
• si el proceso es el hijo que escribe en la pipe, el vector "pids" contiene {-1, 0}
En el caso de que exista algún problema al crear la pipe o los procesos, la función devuelve -1.
Si todo ha ido bien, la función devuelve 0.
Apartado 1: Implementa la función pifo con las llamadas al sistema que hemos visto en la asignatura.
Ten en cuenta:
• Si existe algún problema creando la pipe, o alguno de los procesos, se tendrá que destruir todo lo que se haya creado en
la función. Es decir, si no se puede crear el segundo hijo, la pipe se tiene que cerrar, y el primer hijo se tienen que eliminar.
• La pipe comunica solamente los dos procesos creados. Por tanto, cuando acabe la ejecución de la función pifo, el padre
no conoce la pipe.
• En la solución no hace falta que incluyas el código de comprobación de errores para las llamadas al sistema.
El siguiente código es un ejemplo de utilización de la nueva función pifo. Este programa implementa la
funcionalidad "ls -l | wc -l".
int main ()
{
int pids[2];
if (pifo (pids) == -1)
error ();
/* Algo ha ido mal */
if ((pids[0] != 0) && (pids[1] == 0))
{
/* hijo que escribe en la pipe, ejecuta ls -l */
execlp ("ls", "ls", "-l", (char *) 0);
exit (1);
}
if ((pids[0] == 0) && (pids[1] != 0))
{
/* hijo que lee de la pipe, ejecuta wc -l */
execlp ("wc", "wc", "-l", (char *) 0);
exit (1);
}
if ((pids[0] != 0) && (pids[1] != 0))
{
/* padre */
wait (&pids[0]);
wait (&pids[1]);
}
exit (0);
}
Apartado 2: Mejora la función pifo para que devuelva en el vector de pids, el pid del proceso hermano, en vez
de -1, a cada uno de los procesos hijo creados:
• si el proceso es el padre, el vector "pids" contiene los pids de los dos hijos {pid del que lee, pid del que escribe}
• si el proceso es el hijo que lee de la pipe, el vector "pids" contiene {0, pid del que escribe}
• si el proceso es el hijo que escribe en la pipe, el vector "pids" contiene {pid del que lee, 0}
Pregunta 5. Informació de l’inode (0.5 punts)
Pregunta 3. Instrucciones en orden (2 punts)
Queremos asegurar que la ejecución de una instrucción de un proceso (o flujo) se produce siempre después de la
ejecución de otra en otro proceso (o flujo). Para ello, utilizaremos diferentes mecanismos, pero el objetivo será
siempre que la instrucción INS2 en el proceso/flujo PF2 se ejecute después de la instrucción INS1 del
proceso/flujo PF1. Los mecanismos a utilizar serán cuatro: a) Semáforos, b) Una pipe sin nombre, c) Una pipe
con nombre y d) Signals (excepciones UNIX)
Apartado 1
Antes de resolver el problema, dinos, en general, para cada uno de los mecanismos anteriores, cuándo es lo más
adecuado aplicarlo para el caso de dos procesos, para el caso de dos flujos, y si podría ser utilizado para ambos
casos.
Raona perquè els dissenyadors del sistema UNIX van decidir que a l’inode d’un fitxer es guardés informació
(proteccions, UID, tamany,...) però NO el nom del fitxer.
Pregunta 6. Crides i pipes (1 punt)
Quines de les següents sis crides al sistema té sentit que s’apliqui a una pipe? i a una named pipe?
Crides: mknod,open, close, lseek, write, stat
Pregunta 7. Taules i taules (1 punt)
Sabem que un programa executarà la següent sequència d’instruccions, i cap crida a sistema ens tornarà un error.
Apartado 2
Programa ahora los cuatro casos a)-d): muestra el código de inicialización y la parte anterior y/o posterior a las
instrucciones INS1 e INS2 utilizando para cada caso únicamente el mecanismo pedido; presenta, para cada caso,
la parte de inicialización y en dos columnas los procesos o flujos, de la forma:
Inicializacion:
..........
..........
Procesos/flujos:
PF1
.....
INS1
......
PF2
......
INS2
......
Pregunta 4. Executables (1.5 punts)
Tenim al nostre directori tres executables: mi_A, mi_wc i mi_cat. La mida de les parts de cada programa és la
següent:
Executable Codi
Dades Pila
mi_A
1500 B 800 B 1024 B
mi_cat
2100 B 100 B 2048 B
mi_wc
1000 B 512 B 1024 B
A més tenim el fitxer "mifile" que ocupa 10 KB.
Tenim un sistema de gestió de memòria paginat (pur, no swap, no paginació sota demanda, ...) amb pàgines de
mida 1KB. Codi, dades i pila es carreguen en memòria física en pàgines separades. L’espai de memòria dels
processos mi_A, mi_cat i mi_wc no creix dinàmicament. El programa mi_cat és una versió pròpia de la comanda
’cat’, i mi_wc de ’wc’ de Unix.
Si executem el programa mi_cat amb un argument
$ mi_cat mifile
<-------------------------------------------------(0)
mknod ("mipipe", S_IFIFO | 0666);
pipe (p);
<-------------------------------------------------(1)
switch (fork ())
{
case 0:
fd = open ("f1", O_RDONLY);
dup2 (fd, 0);
read(0 ,&variable, 3);
dup2 (p[1], 1);
<-------------------------------------------------(2)
close (p[0]);
close (p[1]);
close (fd);
execlp ("pr1", "pr1", NULL);
default:
dup2 (p[0], 0);
close (1);
fd = open ("mipipe", O_WRONLY);
<-------------------------------------------------(3)
close (p[0]);
close (p[1]);
execlp ("pr2", "pr2", NULL);
}
Dins el S.O. Unix, siguin les taules de canals i de fitxers oberts (TC i TFO respectivament) al punt (0) com segueix
(només els canals 0, 1 i 2 estàn ocupats):
1) Quantes pàgines de memòria es fan servir com a màxim durant l’execució degut a aquest procés? Justifica-ho.
TC
Imaginem que el procés mi_A llença l’execució de l’equivalent a la comanda "mi_cat mifile | mi_wc -l",
utilitzant fork i exec. Sabem que el programa mi_A escriu per la sortida estàndar la paraula "final" quan mi_wc ha
acabat.
comptador
TFO
mode
punter lectura/escriptura
0
1
r
0
1
2
w
0
2
2) Quin és el màxim de memòria que es pot necessitar degut a l’execució? Raona-ho
3) Just abans d’executar la crida a sistema exit() de mi_wc, quantes pàgines s’ocuparan com a mínim? Raona a
quins processos pertanyen
4) Si en comptes de "mi_cat mifile | mi_wc -l" el procés mi_A llancés a executar l’equivalent a la
comanda "mi_cat mifile | mi_wc -l >fileout", com canvia la quantitat de memòria utilitzada?
3
4
...
5
...
Dibuixa l’estat de les entrades de la TC i la TFO als punts (1), (2) i (3) del procés implicat en cada cas, tot seguint
l’esquema de les taules proposat.
Descargar