Sistemas
Operativos
Convocatoria
de junio, año 2000.
Soluciones
del examen
1. TEST
(1,a) (2,b) (3,b) (4,c) (5,a) (6,d) (7,d)
(8,d) (9,a) (10,c) (11,c) (12,a) (13,a) (14,b) (15,d)
2. Cuestiones sobre Nachos
-
La operación Yield() cede la CPU a un hilo de la cola de preparados
del planificador, mientras que el hilo que la invoca se inserta al final
de dicha cola. En el caso de que la cola de preparados esté vacía,
entonces no se produce cesión alguna de CPU y el hilo que la invoca
se sigue ejecutando.
-
La política de memoria empleada inicialmente es la contigua de una
sola partición, soportada sobre un hardware de paginación.
-
Mediante una llamada al sistema, una interrupción o una excepción.
Todas ellas son interceptadas por el emulador MIPS del Nachos, el cual
invoca a la rutina manejadora de excepciones ExceptionHandler( ) ya en
modo núcleo.
El paso de modo núcleo a modo usuario se hace
al invocar a machine->Run(), que entrega el control al emulador MIPS; o
bien cuando la función ExceptionHandler() retorna.
-
Los programas de usuario se compilan por separado del Nachos porque éstos
no forman parte del sistema operativo y son programas autónomos,
con su propia función main(), que se cargan dinámicamente
a voluntad del usuario. Las opciones de compilación, las bibliotecas
de funciones y los pasos necesarios para dejarlos listos para ejecutar
son distintos.
Se utilizan compiladores diferentes, en nuestro caso, debido
a que se ejecutan en máquinas diferentes: el NACHOS corre sobre
una máquina LINUX que utiliza un microprocesador Intel (se utiliza
el compilador nativo de la máquina LINUX) y los programas de usuario
del NACHOS que utilizan una máquina MIPS emulada, para lo cual se
requiere un compilador que genere código MIPS.
3. Cuestión sobre memoria:
Si realizamos la traza de ambas políticas,
observamos que la política LRU incurre en 7 fallos de página,
mientras que la óptima sólo da 6 fallos. Una política
da mejores resultados cuantos menos fallos de página produzca, luego
en este caso la óptima da un mejor resultado.
La decisión equivocada de la LRU
ha sido escoger como víctima la página 4 en uno de los últimos
accesos.
ÓPTIMA:
(4,-,-) (4,2,-) (4,2,1) (4,2,1) (3,2,1) (3,2,1)
(3,2,1) (4,2,1) (4,2,1) (4,2,1) (4,2,3) (4,2,3) (4,2,3) (4,2,3) (4,2,3)
LRU:
(4,-,-) (2,4,-) (1,2,4) (2,1,4) (3,21) (1,3,2)
(2,1,3) (4,2,1) (1,4,2) (2,1,4) (3,2,1) (2,3,1) (4,2,3) (2,4,3) (3,2,4)
4. Cuestión sobre ficheros:
En todos los supuestos, el archivo entero
se pierde si el daño se produce en el bloque donde está la
información de control del archivo (bloque de comienzo, longitud,
etc.), así que hemos de encontrar casos distintivos de cada política.
En el caso de la contigua,
si se pierde un bloque de datos, el resto de ellos sigue siendo accesible,
puesto que la información de ubicación no resulta dañada.
En la política encadenada, también se pierde el acceso a
la totalidad del archivo si se daña el primer bloque de datos, dado
que perdemos el resto de la cadena. (Esto no ocurriría si se utilizaran
encadenamientos dobles, o en sistemas basados en FAT). Por su parte, la
política indexada tiene el riesgo de que se dañe el bloque
de índices, en cuyo caso no podríamos acceder a ningún
bloque del archivo. Por tanto, la probabilidad es mayor para las políticas
encadenada e indexada respecto a la contigua. Entre la encadenada y la
indexada vemos que la probabilidad es más o menos similar (aprox.
1 bloque sobre N posibles). Eso sí, si consideramos encadenamientos
dobles, la indexada tendría más probabilidad.
5. Implementación del planificación
usando cerrojos y variables de tipo condición
En este propuesta se utiliza el estilo
Hoare para las varibles de tipo condición. Recuérdese que
en este estilo cuando un proceso realiza una operación "signal"
sobre una variable de tipo condición cede el cerrojo al proceso
que había hecho una operación "wait" y se bloquea. El proceso
que había realizado la operación "wait" entra en ejecución
inmediatamente. El proceso que hizo la operación "signal" tiene
que esperar a tomar de nuevo el control del cerrojo para seguir ejecutándose.
Un ejercicio que se plantea al lector es
comprobar si la solución aportada serviría si se utilizaran
varibales de tipo condición según el estilo de Mesa y de
no ser válida aportar una solución.
Clase Planificador
Sección de datos públicos globales:
Proceso: variable entera que identifica el proceso que tiene el recurso asignado
Ocupado: variable booleana que indica si el recurso está asignado o no.
Llave: variable de tipo cerrojo
Turno: variable de tipo condición, vinculada al cerrojo "Llave"
Nespera: variable entera que indica cuántos procesos esperan por el recurso
Valores iniciales:
Ocupado = falso;
Proceso = - 1;
Nespera = 0;
Sección de funciones públicas:
Función Pido_Recurso( variable entera pid )
{
Retorno: variable local entera;
Llave.adquiero;
Si ((Ocupado=cierto)AND(Proceso=pid)) Entonces
Retorno = -1;
Si no
Si (Ocupado=cierto) Entonces
Nespera = Nespera + 1;
Turno.wait;
Nespera = Nespera – 1;
Fin si
Ocupado = cierto;
Proceso = pid;
Retorno = 0;
Fin Si
Llave.libero;
Return(Retorno);
}
Función Libero_Recurso( variable entera pid )
{
Retorno: variable local entera;
Llave.adquiero;
Si ( (Ocupado = falso) OR (Proceso /= pid) ) Entonces
Retorno := -1;
Si no
Ocupado = falso;
Si ( Nespera > 0 ) Entonces
Turno.señal;
Fin si
Retorno = 0;
Fin Si
Llave.libero;
Return (Retorno);
}
Fin de la clase