Sei sulla pagina 1di 7

Examen final de Sistemas Operativos Solución

25 de Junio de 2002. Segundo curso de Ingenierías Técnicas de Informática de Sistemas y de Gestión, URJC.

Problema 1 (1 puntos)

Haz un script que muestre los ficheros (sólo los ficheros normales) que tengan al menos 10000 octe- tos en el directorio actual. Puedes usar como punto de partida el comando ls -l. Éste es un ejemplo de la sal- ida del mismo.

-rw-rw-r-- 1 anto anto 141264 may 13 18:43 projecte_LCU.pdf

drwxr-x--x 26 anto anto drwxr-x--x 14 anto anto

4096 may 30 20:19 proyectos

4096 dic 24

2000 prv

drwxr-xr-x

9 anto anto

4096 feb 7 12:09 public_html

-rw-rw-r--

1 anto anto 246323 may 3 10:16 sep01.pdf

-rw-rw-r--

1 anto anto 14646 jun 7 18:51 servid~1.adb

Solución

Suponiendo que sólo piden que mostremos los nombres, bastaría un

ls -l | egrep ’^-.*[1-9][0-9][0-9][0-9][0-9] ’

que imprimiría las líneas que contienen al menos cinco dígitos seguidos de un espacio en blanco y comien- zan por - (al exigir que tras los números tengamos un espacio en blanco, eliminamos posibilidad de confusión con nombres de fichero que sean numéricos). Si queremos sólo los nombres podemos cortar el resto de los campos con cut o con awk, dado que todos conoceis cut, en la solución vamos a usar awk:

ls -l | grep ’^-.*[1-9][0-9][0-9][0-9][0-9] ’ | awk ’-F ’ ’{print $NF}’

Problema 2 (2 puntos)

- 2 -

Dado el siguiente trozo de código:

Fd, R, L: Integer; A: System.Address; type Buffer is record Buf: String(1 256); Lon: Integer; end record; P: access to Buffer;

begin

Fd:= Creat("buffer", 8#777#); R:= Lseek(Fd, 256, SEEK_SET); A:= Mmap(0, 256, PROT_READ+PROT_WRITE, MAP_SHARED, Fd, 0); R:= Close(Fd); P:= A; if Fork = 0 then loop

Read(1, P.Buf, 256, P.Lon); exit when P.Lon=0;

end loop;

else

 

while P.Lon > 0 loop R:= Write(0, P.Buf, P.Lon);

end loop;

end if;

a) ¿Qué parece querer hacer el mismo?

b) ¿Qué errores encuentras?

c) ¿Qué mecanismos de Unix podrías usar para coordinar el acceso de los procesos padre e hijo al Buffer? Ten en cuenta que no puedes usar los semáforos que os proporcionamos para la práctica.

Solución

El código parece que está pensado para copiar de la entrada a la salida estándar de tal forma que un proceso lee, el otro escribe y ambos se comunican usando un buffer de memoria compartida.

Hay algunas cosas que suponen errores:

1

El fichero que proyectamos con el mmap se abre tras crearlo con creat y queda abierto WRONLY, con lo que no se puede hacer un mmap que incluya como permiso PROTREAD.

2

Falta una llamada a write tras el lseek para hacer crecer el fichero hasta el tamaño del buffer. El lseek no escribe nada por si solo y por tanto no cambia el tamaño de buffer (que seguirá teniendo 0 bytes). Haría falta escribir tras el lseek un Integer, para hacer que el fichero coin- cida con el tamaño de la estructura de datos.

3

El read debería hacerse del descriptor 0, que es la entrada.

4

El write debería hacerse del descriptor 1, que es la salida.

5

No se comprueban condiciones de error en ninguna de las llamadas.

6

Los procesos no se sincronizan al acceder al buffer, con lo que las condiciones de carrera harán que el programa no funcione.

Para coordinar el acceso al buffer se podrían emplear dos pipes. Podríamos crearlos antes del fork

con:

pipe(canread);

pipe(canwrite);

Y luego cambiar el código como sigue:

- 3 -

write(canread(1), " ", 1); if Fork = 0 then loop

Read(canread(0), temp, 1, X); Read(1, P.Buf, 256, P.Lon); Write(canwrite(1), " ", 1); exit when P.Lon=0;

end loop;

else

 

while P.Lon > 0 loop Read(canwrite(0), temp, 1, X); R:= Write(0, P.Buf, P.Lon); Write(canread(1), " ", 1);

end loop;

end if;

De tal modo que el lector no sobreescribe el buffer hasta que el escritor terminó de escribirlo, y el escritor no escribe ningún buffer hasta que dicho buffer se ha leido.

Problema 3 (2 puntos)

Se pide escribir un programa concurrente que conste de dos procesos concurrentes A y B sincroniza- dos mediante semáforos de tal manera que el resultado final de la ejecución sea que los procesos escriban en la salida estandar en secuencia lo siguiente:

" Primero el proceso A debe escribir: ‘‘Soy A’’

" Segundo el proceso B debe escribir: ‘‘Soy B’’

" Tercero el proceso A debe escribir: ‘‘Termino A’’

" Cuarto el proceso B debe escribir: ‘‘Termino B’’

Solución

Podría quedar como sigue:

Acontinua: Semaphore := 0; Bcontinua: Semaphore := 0;

Program A is begin

Put("Soy A");

signal(Bcontinua);

wait(Acontinua);

Put("Termino A");

signal(Bcontinua);

end;

Program B is begin

wait(Bcontinua);

Put("Soy B");

signal(Acontinua);

wait(Bcontinua);

Put("Termino B");

end;

Problema 4 (3 puntos)

- 4 -

Tenemos un sistema operativo que tiene las siguientes características:

" Memoria virtual con paginación bajo demanda.

" Planificación con dos niveles de prioridad dinámica que utiliza round-robin (quantum de 100ms) den- tro del mismo nivel de prioridad y recalcula la prioridad según la siguiente regla: Si se consume el cuanto se baja la prioridad, en caso contrario se sube. Al principio de cada ráfaga los procesos entran en la prioridad alta.

" Tabla de páginas de dos niveles, con 1024 entradas tanto en las tablas de primer nivel como en las de segundo nivel.

" Direcciones virtuales de 32 bits.

En dicho sistema tenemos dos procesos que van a ejecutar a partir de t=0. Ambos procesos se com- portan como sigue:

" Se meten en un bucle durante 50ms, usando las páginas 2 y 4 de memoria virtual.

" Hacen entrada/salida durante 100ms.

" Se meten en un bucle durante 150ms, usando la páginas 2 y 3 de memoria virtual.

Disponemos de 4 marcos de página libres (además de los empleados para guardar el sistema opera- tivo y las tablas de páginas de los dos procesos, que nunca se liberan bajo ningún concepto).

Se pide:

" Dibuja un diagrama de planificación (tiempo/procesos) donde indiques el estado de cada proceso (listo/ejecutando/bloqueado) para cada intervalo de tiempo. Has de indicar también en qué nivel de prioridad (alto/bajo) se encuentra cada proceso.

" Indica para intervalo del diagrama anterior cual es el contenido de las tablas de páginas (número de marco, bits de presente/ausente, R y M) de cada proceso y qué páginas están en cada uno de los mar- cos. Supón que el algoritmo de reemplazamiento es FIFO.

Puedes suponer que el tiempo necesario para traer una página de disco o para expulsarla es 0, igual que el tiempo necesario para cambiar de contexto.

Solución

La planificación puede verse en la figura 1. El único punto destacable es que hay un intervalo en que ninguno de los dos procesos está listo para ejecutar, por lo que el sistema ejecutaría la tarea idle (que se omite).

. . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
run (hi)
.
blk (hi)
.
.
run (hi)
.
rdy (lo)
.
run (lo)
.
.
.
.
.
.
.
.
.
P1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
rdy (hi)
.
run (hi)
.
blk
.
. (hi)
rdy (hi)
.
run (hi)
.
rdy (lo)
.
run (lo)
.
.
.
.
.
.
.
.
P2 .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Figura 1. Los cambios de contexto están indicados con líneas verticales discontinuas. En la figura, rdy indica listo para ejecutar , run indica ejecutando , blk indica bloqueado , hi indica prioridad alta y lo indica prioridad baja .

En cuanto a las tablas de páginas, dado que ninguno de los procesos accede a páginas con número mayor a 1024, sólo se usará la primera tabla de segundo nivel en ambos procesos. Inicialmente, todas las entradas de la tabla de primer nivel estarán inválidas hasta la primera referencia a memoria de los procesos considerados. Tras ésta, la primera entrada de la tabla de primer nivel en ambos procesos estará marcada como presente , y contendrá el número de marco de la primera tabla de segundo nivel del proceso consid- erado.

Las tablas de segundo nivel de ambos procesos parten con todo inválido ( Ausente ). Indicamos a

- 5 -

continuación cómo quedan estas en cada intervalo de planificación. En cada entrada indicamos el número de marco ( xxxxxxx si no lo sabemos o no nos importa), el bit de presente/ausente ( P/A ), el bit R de referenciado ( ? cuando no lo sabemos), y el bit M de modificado ( ? cuando no lo sabemos).

t=0 Nada aún. t=50 Marcos 2 de P1 4 de P1 X X P1 xxxxxxxx
t=0 Nada aún.
t=50
Marcos
2
de P1
4
de P1
X
X
P1
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx A ? ?
xxxxxxxx A ? ?
00000000
P
R ?
xxxxxxxx A ? ?
00000001
P
R ?
1024
xxxxxxxx A ? ?
t=100

Marcos

P2

Ninguna

2 de P1

4

de P1

2

de P2

4 de P2

P1

P2

xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
 

xxxxxxxx A ? ?

 

xxxxxxxx A ? ?

xxxxxxxx A ? ?

xxxxxxxx A ? ?

00000000

P R

?

00000002

P R

?

xxxxxxxx A ? ?

xxxxxxxx A ? ?

00000001

P R

?

00000003

P R

?

1024

1024

xxxxxxxx A ? ?

xxxxxxxx A ? ?

t=150 Siguen igual.

t=250 P1 referencia las páginas 2 y 3. Todo depende de cuantas referencias y en qué orden se hagan. Suponemos que tenemos una referencia a la 2 y luego otra a la 3. La 2 está, pero para incluir la 3 hay que expulsar una de las que ya tenemos, según una política FIFO. Luego la que expulsamos es la página 2 de P1.

Marcos

- 6 -

3

de P1

4

de P1

2

de P2

4

de P2

P1

P2

xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
 

xxxxxxxx A ? ?

 

xxxxxxxx A ? ?

xxxxxxxx A ? ?

xxxxxxxx A ? ?

00000000

A R ?

00000002

P R

?

00000000

P R

?

xxxxxxxx A R ?

00000001

P R

?

00000003

P R

?

1024

 

1024

xxxxxxxx A ? ?

xxxxxxxx A ? ?

t=350 P2 referencia las páginas 2 y 3. Todo depende de cuantas referencias y en qué orden se hagan. Suponemos que tenemos una referencia a la 2 y luego otra a la 3. La 2 está, pero para incluir la 3 hay que expulsar una de las que ya tenemos, según una política FIFO. Luego la que expulsamos es la página 4 de P1.

Marcos

3

de P1

3

de P2

2

de P2

4

de P2

P1

P2

xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
xxxxxxxx P ? ?
1024
xxxxxxxx A ? ?
xxxxxxxx P ? ? 1024 xxxxxxxx A ? ?
 

xxxxxxxx A ? ?

 

xxxxxxxx A ? ?

xxxxxxxx A ? ?

xxxxxxxx A ? ?

00000000

A R ?

00000002

P R

?

00000000

P R

?

00000001

P R

?

00000001

A R ?

00000003

P R

?

1024

 

1024

xxxxxxxx A ? ?

xxxxxxxx A ? ?

t=400 Si suponemos que ahora nos mantemos usando la página 3, no cambiaría la situación (En caso con- trario tendríamos que volver a traer la 2, escogiendo la siguiente página que entró como víctima para la expulsión).

t=450 Suponiendo ahora que este proceso se mantiene usando la página 4, tampoco cambia nada (En caso contrario tendríamos que traer la página 3, expulsando alguna de las que tenemos ahora mismo).

Hay que decir que si los procesos hacen repetidas referencias a las páginas 3 y 4 en su última ráfaga, tendríamos que paginar bastante mas, dado que con la política FIFO es muy posible (como se ha visto) que expulsasemos una de las que estamos necesitando (la 3 o la 4 de alguno de los dos procesos).

- 7 -

Problema 5 (2 puntos)

Sea un sistema de fichero tipo Unix que gestiona bloques de datos de 4K. Cada nodo-i, además de

otra información,

enlace de indirección doble y un enlace de indirección triple. Responded razonadamente a las siguientes cuestiones:

a) Suponiendo que tenemos una cache de 20 bloques de datos y otra de 20 nodos-i inicialmente vacías, que el nodo-i del directorio raiz se encuentra en memoria principal, y que sólo ejecuta en el sistema el siguiente proceso:

contiene 10 enlaces directos a bloques de datos, un enlace de indirección simple, un

fd1=open("/usr/pablo/practica1");

fd2=open("/usr/jose/practica1");

lseek(fd1,12*4096);

leidos=read(fd1,datos,5);

exit(0);

¿Cuántos accesos a disco realiza el proceso suponiendo que la información de cada directorio que accede cabe en un solo bloque de datos?

b) ¿Tiene fragmentación este tipo de sistema ficheros? ¿De que tipo? ¿Cuál es el tamaño medio de la fragmentación de cada fichero?

Solución

Empezando por el primer open, tenemos que resolver /usr/pablo/practica1 con lo que hacemos los siguientes accesos:

1 Leemos el primer bloque de datos del inodo del directorio raiz. (Buscamos en la tabla usr).

2 Leemos el inodo para usr.

3 Leemos el primer bloque de datos de dicho inodo. (Buscamos en la tabla pablo).

4 Leemos el inodo para pablo.

5 Leemos el primer bloque de datos de dicho inodo. (Buscamos en la tabla practica1).

6 Leemos el inodo para practica1).

Continuando con el segundo open, resolvemos /usr/jose/practica1 teniendo en cuenta que ya tenemos en la cache de inodos el inodo para usr y en la cache de bloques el bloque de datos de ficho inodo, por lo que la primera lectura será:

7 Leemos el inodo para jose.

8 Leemos su primer bloque de datos. (Buscamos en la tabla practica1).

9 Leemos el inodo para practica1).

Ahora continuamos con el lseek, que no realiza acceso alguno a disco. y nos deja posicionados justo al principio del bloque 12 del primer fichero abierto (si empezamos a contar los bloques desde 0). Tras ello leemos 5 bytes, con lo que habrá que leer dicho bloque:

10 Leemos el bloque B apuntado por el primer puntero indirecto simple del inodo que corresponde a

/usr/pablo/practica1.

11 Leemos el bloque apuntado por el tercer puntero presente en B . (el primer puntero apuntará al bloque 10 del fichero, el segundo puntero apuntará al 11, y el tercero es el que nos interesa).

En cuanto a la fragmentación, tenemos algo de fragmentación interna dado que asignamos bloques a ficheros. La fragmentación externa es nula dado que todos los bloques son del mismo tamaño. En media, cada fichero desperdicia la mitad de su último bloque, esto es, 2K por fichero.