SISTEMAS OPERATIVOS TEMA 1: INTRODUCCIÓN AL SISTEMA OPERATIVO ONION

Anuncio
SISTEMAS OPERATIVOS
TEMA 1: INTRODUCCIÓN AL SISTEMA OPERATIVO ONION
TEMA 1: INTRODUCCIÓN AL SISTEMA OPERATIVO ONION
Descripción general
El sistema operativo (S.O.) ONION posee las siguientes características:
• Multiusuario: al ser multiusuario necesitaremos proteger los datos de cada usuario. Para esto
necesitaremos los comandos de login y logout los cuales, dependiendo de un username y un password
tendrán unos privilegios u otros.
• Multiprogramado: esto quiere decir que se pueden tener n procesos ejecutándose al mismo tiempo,
pero si el ordenador solo tiene un procesador se ejecuta un solo proceso y el resto estará bloqueado o
preparados para ser ejecutados. Por lo tanto los estados de un proceso son: run (ejecutándose),
preparado y bloqueado.
• Estructurado en capas: Esto quiere decir que se diferencian diferentes capas según la cercanía al
hardware. Las capas del ONION son la de sistema la BFS (Basic file System) y el núcleo.
Si se modifica el hardware solo se debería modificar la capa del núcleo ya que es la capa más cercana al
hardware. Las llamadas al sistema (system calls) llaman a la capa del sistema, y la forma de comunicarse esta
con las demás capas es mediante llamadas especiales, pero si se quiere comunicar con la capa del núcleo antes
debe pasar la información por la capa de BFS. Cada capa resuelve un determinado problema y si una capa no
es capaz de resolver dicho problema se baja a la capa siguiente.
Visión externa
La visión externa de un sistema operativo es lo que ofrece este al exterior.
Dispositivos
Los dispositivos que nos ofrece ONION son de dos tipos, físicos (consola, terminal, impresora y el disco) i
lógicos (mailbox y nulo).
• Consola: la consola esta formada por un teclado y una pantalla por donde se comunica el usuario y el
ordenador de forma interactiva. La consola es donde trabaja el usuario principal. A la consola se le
asocia un interprete de comandos al igual que a los terminales.
• Terminal: igual que la consola pero que está conectado a la lincea serie.
• Mailbox: a diferencia con UNIX, donde un mailbox es un archivo temporal, en ONION es un buffer
de memoria que sirve para comunicar y sincronizar procesos.
• Nulo: este dispositivo sirve para borrar, ya que la información que se inserte en dicho dispositivo ya
no se puede recuperar, porque no podemos leer de este dispositivo.
La conexión entre ordenadores con el sistema operativo ONION queda reflejada en el siguiente gráfico:
Como se puede observar la conexión de los ordenadores se realiza mediante los terminales, donde cada
terminal tiene su intérprete de comandos el cual no enviará ningún prompt que indique que están esperando
una orden nueva.
1
Ahora veremos las características de los dispositivos:
• ECHO/NO ECHO: solo tiene sentido en dispositivos de entrada/salida. Significa que lo que se
introduce por la entrada sale por la salida. Por defecto la característica echo está activada (consola y
terminal).
• COOKED/RAW: cooked significa que el dispositivo es capaz de interpretar caracteres especiales
(return, delete, tabulador, etc.). La consola y el terminal tienen por defecto la característica de cooked
y el mailbox, la impresora y los ficheros la raw.
• EOT/NOEOT: característica de fin de transmisión. Indica si un proceso ha dejado de trabajar con
algún dispositivo o se cierra un canal de escritura en el terminal. El terminal y el mailbox tienen por
defecto la característica de Noeot.
• SPOOL/NOSPOOL: solo tiene sentido en la impresora, donde por defecto esta en nospool. La
impresora es un dispositivo no compartible, es decir, solo un proceso puede acceder, y además es
lenta. Debido a este motivo y para poder permitir que varios procesos puedan acceder a la impresora
existe un dispositivo intermedio que permite que varios procesos puedan imprimir a la vez gracias a
que crean un fichero temporal. Aquí interviene SPOOL el cual va cogiendo estos ficheros temporales
y los envía a la impresora uno tras otro para que sean impresos. De este modo la impresora pasa a ser
compartible.
• PERMANENTE/NO PERMANENTE: característica de los mailbox. Si un mailbox es permanente
este guarda la información que se le introduce aunque el proceso que lo invoca termine, en cambio en
un mailbox no permanente cuando el proceso que lo invoca termina la información de dicho mailbox
se pierde. Por defecto los mailbox son permanentes.
Interprete de comandos
El interprete de comandos muestre el prompt formado solo por el símbolo del dólar. Además acepta los
caracteres de redireccionamiento de entrada, salida y error.
redireccionar salida >
redireccionar entrada <
redireccionar error ^
nom hará referencia a un fichero o a un dispositivo y nom_fitxer a un fichero.
El interprete de comandos reconoce los siguientes comandos:
• Comandos de manejo de ficheros y dispositivos:
$ dir [>nom]
$ copy [<nom] [>nom]
$ del nom_fitxer
$ mou nom_fitxer_vell nom_fitxer_nou (cambio del nombre del fichero)
$ prot nom [prot] [uid] (modifica las protecciones y el ususario del nom)
$ set nom característica (característica de los dispositivos)
2
• Gestión de procesos:
$ run nom_fitxer [<nom][>nom][^nom][parámetres]
Ejecuta un proceso pero espera a que termine el proceso hijo.
$ spawn nom_fitxer [<nom][>nom][^nom][parámetres]
Ejecuta el proceso hijo y el padre de forma concurrente.
$ stop id_proces.
$ sys [>nom]
Da información sobre el sistema (tiempo des de la puesta en marcha del sistema, y indica que fichero ejecuta
el proceso y el identificador de usuario, uid).
$ login [nmbre usuario]
$ logout
Visión interna y Llamadas al sistema
Llamadas sobre la capa sistema
La única puerta de acceso a los sistemas operativos son la llamadas al sistema. Estas no son mas que un
conjunto de llamadas a funciones las cuales implementan los servicios ofrecidos por el sistema. En el caso de
ONION el conjunto de llamadas serán las primitivas que el nivel más externo (nivel sistema) ofrecerá a los
usuarios.
Como hemos dicho el único modo de comunicar las diferentes capas del S.O. es a través de llamadas.
El nivel sistema es el que servirá de interprete entre los usuarios del S.O. y el mismo sistema. Las primitivas
constituirán lo que se llama conjunto de llamadas al sistema. Este nivel ofrecerá a los programas de usuario
una máquina virtual de alto nivel que garantizará una serie de servicios a los usuarios. Estos servicios pueden
agruparse de la siguiente manera:
• Entrada/salida: ONION ofrece E/S independencia del dispositivo sobre el que trabajan (la E/S se
realiza con dispositivos virtuales, los cuales se identifican por un canal). Para garantizar esta
independencia del dispositivo las llamadas
Llegir (canal, buffer, longitud)
Escriure (canal, buffer, longitud)
Actuaran sobre canales que podrán representar cualquier dispositivo o fichero. Estas operaciones aran un
acceso secuencial i serán asíncronas. Estas llamadas no se bloquearán aunque no hayan terminado su trabajo y
se les invoque de nuevo. Las llamadas
Esperar (id_io) −> nos indica como ha terminado un dispositivo
Cancel−lar (id_io2)
3
Ofrecerán la posibilidad de anular una operación de E/S i de sincronizar la finalización con la ejecución del
resto del programa.
Hay dos formas de asociar el canal al dispositivo:
· Mediante la herencia: el proceso hijo hereda la tabla de canales del padre. Por ejemplo:
executar_programa(fitxer, input, output, error, p1,..., (char *)0
donde input, output y error indica que canal se quiere para la entrada, salida y error del proceso, si aquí se
indica (char *)0, quiere decir que los canales son los mismos que los del padre que lo ha invocado.
· Mediante las llamadas
obrir (canal, nom, modo, protecciones)
tancar (canal)
las cuales asocian un dispositivo a o un fichero a un canal, y liberan un canal determinado permitiendo así una
futura asociación con otro dispositivo o fichero, respectivamente.
En ONION solo disponemos de 5 dispositivos virtuales, esto quiere decir que solo tenemos cinco entradas a la
tabla de canales. Cada dispositivo apunta a un solo descriptor de dispositivos.
• Ficheros: ofreceran a los usuarios tres funciones sobre ficheros heredados del nivel BFS. Seran las de
leer directorio del disquete, borrar un fichero i cambiar el nombre a un fichero.
• Control de procesos: dos de las tareas fundamentales de todo el sistema operativo son lacreación i
destrucción de procesos. En el caso de un sistema multiprogramado como ONION la creación de
procesos implicrá una ejecución concurrente del proceso crador y del proceso creado.
Executar_programa (fitxer, input, output, error, p1,..., (char *)0
Crea un proceso nuevo, creando su PCB con su tabla de canales correspondiente. En el nivel BFS se hace la
llamada
Crear_pcb_bfs (pid, prioritat, codi, pila)
Y se crea otra PCB en este nivel y se hace una llamada en el nivel de núcleo
Crear_pcb_nuc (codi, pila, prioritat, quantum, id_proc)
La cual crea otra PCB en este nivel y donde quantum es el tiempo de CPU asignado a este proceso.
Fi_programa (codi_retorn)
Stop (id_proces)
Esperar_fill (&codi_retorn)
Esta última llamada realiza una sincronización entre el proceso padre e hijo, donde el proceso padre se
bloquea hasta que termina el proceso hijo. Con stop lo que realizamos es que el proceso indicado finalice por
lo tanto es como si lo destruyéramos, en cambio fi_programa hace que el proceso que invoca esta llamada
4
termine, seria como si se autodestruyera. Según como se termine un proceso codi_retorn de esperar_fill tendrá
dos valores diferentes, −2 si el proceso que esperaba se ha terminado con stop y codi_retorn si el proceso se
ha terminado con fi_programa.
• Temporización: permiten que los procesos de usuario puedan bloquearse durante un cierto número de
segundos en espera de algún acontecimiento.
• Protección: será en este nivel donde se hará la gestión de usuarios i todas las comprobaciones
necesarias para garantizar la protección de procesos y de dispositivos. Existen dos usuarios en un
sistema con ONION: super−Onion (que es el sistema y que tiene todos los privilegios) y el ordinario.
Los procesos solo podrán ser destruidos por su propietario o por el super−ONION. También será
posible para el super−Onion cambiar el propietario de un proceso. Al haber el usuario ordinario y el
resto de usuarios se definen dos dominios de protección, para el usuario y para el resto de usuarios. La
protección puede ser de lectura, escritura o lectura/escritura.
Tener permiso de ejecución sobre un dispositivo es tener la posibilidad de modificar las características del
dispositivo. Cuando un usuario abre un dispositivo, y es el primero en abrirlo, este se convierte en el
propietario y el resto, por lo tanto no podrá acceder si no se cambian las protecciones.
Llamadas sobre la capa BFS
El BFS será un nivel intermedio entre la independencia de dispositivos que ofrece el nivel sistema i la
dependencia respecto al hardware de la maquina que tendremos en el nivel inferior (núcleo).
Este nivel ofrecerá primitivas especificas para cada dispositivo que permitirán implementar las E/S que el
nivel sistema ofrecía a los usuarios. DE toda forma estas primitivas diferenciadas para cada dispositivo serán
independientes del hardware de la maquina ya que utilizaran las funciones que el nivel mas bajo les ofrecerá.
Las funciones de este nivel pueden agruparse de la siguiente forma:
• Acceso i manejo de ficheros (la mas importante en este nivel).
• Entrada/salida de dispositivos.
• Control de procesos.
• Temporización.
• Planificación de la utilización de recursos.
• Protección de ficheros.
En este nivel tenemos dos tablas diferentes:
• TFA (tabla de ficheros abiertos): aquí hay una entrada abierta por cada fichero diferente abierto. Tiene
un campo que indica cuantas veces se ha abierto el mismo fichero y un puntero a la FAT.
• FAT (File Allocation Table): indica a cada registro lógico correspondiente a un fichero donde se
encuentra el registro físico. Esta tabla nos dice para todos los ficheros en que bloque físico se
encuentra sus registros lógicos.
Con cada lectura, en este nivel, se leen 512 bytes que es lo mide un bloque entero.
Llamadas sobre la capa núcleo
Es el nivel más próximo al hardware de la maquina. Por debajo de este encontraremos los controladores de los
dispositivos, la memoria y el procesador. Este nivel depende totalmente de la maquina sobe la qual estemos
trabajando y se habrá de modificar cada vez que queramos transportar nuestro S.O. a un nuevo computador.
La función del núcleo será la de liberar a los niveles superiores del manejo de los dispositivos. Des de este
5
nivel programaremos todos los controladores de la maquina de tal forma que los niveles superiores puedan
excluirse de esta función. Así mismo será el único nivel que gestionará los registros del procesador i peor lo
tanto, se habrá de utilizar rutinas en ensamblador. Des de este nivel ofreceremos al nivel BFS una maquina
virtual con los siguientes conjuntos de servicios:
• Gestión de procesos (la más importante en este nivel).
• Gestión del tiempo.
• Sincronización i comunicación entre procesos.
• Entrada/salida sobre dispositivos.
• Gestión de memoria.
Para cada nuevo proceso tendremos una pila en el espacio de memoria del usuario, y una PCB en el nivel del
núcleo o espacio de direcciones del sistema, aunque en este nivel también seria bueno tener una pila.
Los procesos se pueden encontrar en diversos estados (solo se puede ejecutar un proceso y el resto de
procesos activos estarán en estado ready o bloqueados). La política para ver que proceso se ejecuta és la
Round−Robin por prioridades.
Esta política significa que la CPU siempre la ocupará el proceso mas prioritario, y si hay varios con la misma
prioridad entonces cuando se acaba el quantum del proceso este pasa a estado ready (pasa a la cola ordenada
por prioridades) y el primero de esta cola es el que se ejecuta. En la cola se inserta, el proceso, en el último
lugar de los procesos con la misma prioridad. Dentro de esta política de Round−Robin existen diversas
opciones:
• Apropiación inmediata: los procesos se pueden bloquear, y por lo tanto pasa a ejecutarse el siguiente
proceso en estado ready. Si se desbloquea y este es más prioritario que el que se está ejecutando,
entonces la rutina que desbloquea el proceso hace que se ejecute inmediatamente y el que se estaba
ejecutando pase a estado ready.
• Apropiación diferida: la rutina de desbloqueo hace que el proceso desbloqueado pase a ready y que se
ejecute, si es mas prioritario que el que se está ejecutando, en la siguiente interrupción de reloj. La
rutina que se encarga de ver si se le acaba el quantum al proceso será la encargada de hacer el
intercambio de procesos.
TEMA 2: PROCESOS
Planificadores
El objetivo de los planificadores es maximizar la utilización de la CPU referido a procesos del usuario.
Existen tres tipos de planificadores:
• Planificadores a largo plazo (Large term): estos planificadores deciden que procesos entran en el
sistema. Decide el grado de multiprogramación. Este planificador carga el ejecutable, asigna un PCB i
las pilas de usuario y de sistema y por último asigna los recursos.
• Planificadores a corto plazo (Short term): en la CPU solo se puede ejecutar un proceso y por lo tanto
hay procesos en estado ready o bloqueados. Este planificador decide que proceso, entre uno de los que
están listos y el que se esta ejecutando, se ejecutará en la CPU.
• Planificador a medio plazo (Medium term): este planificador se utiliza en sistemas con memoria
virtual. Un fallo de pagina se produce cuando la CPU da una dirección de memoria que no se
encuentra en la memoria física. Si la memoria se divide en muchas paginas se puede producir
Trashing, que consiste en que se ejecutan más fallos de pagina que procesos.
La utilización de la CPU aumenta con el aumento de la multiprogramación pero puede llegar a un momento
6
en que la utilización de la CPU desciende por los fallos de paginas. El planificador de medio plazo entra en
acción en este punto de Trashing. Este planificador decide que procesos se quitan de la CPU en este punto, lo
que hace es sacar, normalmente, los procesos bloqueados que pasan a un área de swap (disco), aunque
también puede sacar procesos en estado ready.
Planificador a corto plazo
Los criterios de este planificador son lo siguientes:
· Justicia: se intenta aumentar la justicia, es decir, que todos los procesos tendrían que recibir algún tiempo de
CPU. Lo contrario a este criterio es la inanición, haciendo que procesos nunca se ejecuten.
· Eficiencia: este criterio tiene que ser lo más eficiente posible, por lo tanto se intenta maximizar. Este criterio
mantiene la CPU el tiempo máximo con procesos de usuarios.
· Productividad: (Throughput) este criterio intenta maximizar el número de trabajos procesados por unidad de
tiempo. Tiene prioridad los procesos cortos frente a los largos.
· Tiempos de retorno (Turnaround): este criterio intenta minimizar este tiempo, que consiste en el intervalo
desde que mandamos que se ejecute un proceso hasta que termina. (Característico de los sistemas batch).
· Tiempo de respuesta: criterio que minimiza el tiempo que transcurre desde que hay una petición E/S hasta la
respuesta del dispositivo E/S. Se utiliza en sistemas interactivos.
· Tiempo de espera: minimiza el tiempo de espera en la cola de ready.
Políticas/Algoritmos de planificación
Políticas
Existen dos tipos de políticas:
• Apropiativa: un proceso que ocupa la CPU, abandona la CPU de forma no voluntaria, ni termina ni se
bloquea, ya que el sistema se la quita. Esta ploítica tiene dos variantes la apropiativa inmediata y la
diferido (estas se basan si se introduce en la siguiente interrupción de reloj o se introduce
inmediatamente).
• No apropiativa: el proceso se bloquea o termina por su voluntad.
Algoritmos
FCFS: el primero en legar es el primero servido. Sigue una política no apropiativa. SI un proceso se bloquea,
entra en la CPU otro proceso, pero si el bloqueado se desbloquea hay dos opciones: ponerlo en la cola de
ready o ejecutarlo, pero al tener una política no apropiativa el proceso bloqueado pasará a ready pero como si
hubiera acabado de llegar.
SJF: se ejecuta el proceso más corto. Sigue una política no apropiativa. Este tiene una variante que consiste en
la versión apropiativa.
SJF (Shortetst Job First) es útil en sistemas batch. El propio usuario es el que da el tiempo que va a durar el
proceso. En sistemas interactivos nos interesa saber cuanto va a durar la siguiente ráfaga de CPU, pero no se
calcula el tiempo exacto sino que se hace una aproximación con la siguiente fórmula:
7
n+1= tn +(1−)n
donde: n+1: es el tiempo de la siguiente ráfaga.
n: es el tiempo de la ráfaga.
tn: es el tiempo de la ráfaga anterior.
: es un valor entre 0 i 1.
Des de que le asignamos el tiempo hasta que finaliza este tiempo, el proceso se ejecutará y si el proceso
necesita mas tiempo este seguirá ejecutándose en la CPU hasta que lo abandone por voluntad (finalice o se
bloquee).
SRT (Shortest remaining Time) és la versión apropiativa del algoritmo SJF y lo que hace es que cuando un
proceso se desbloquea o se crea un proceso y el tiempo de ráfaga es menor que el tiempo de ráfaga del
proceso que se esta ejecutando, se hace un cambio de contexto, el bloqueado se ejecuta y el que se estaba
ejecutando pasa a ready.
Cuando se desbloquea o entra un proceso nuevo, se calcula su tiempo próximo de ráfaga. Si el proceso que se
está ejecutando le queda mas tiempo de ráfaga que nuestro tiempo de ráfaga calculado hacemos el cambio de
contexto.
Por prioridades: es un algoritmo con política apropiativa. Ejecuta el proceso con la mayor prioridad.
Estos algoritmos pueden producir inanición y por lo tanto no cumplen el criterio de Justicia.
Round−Robin: asignamos un determinado tiempo a los procesos (quantum). EL proceso ocupa la CPU el
número de ciclos o interrupciones de reloj que se le indique en el quantum. Este algoritmo sigue una política
apropiativa, ya que expulsamos al proceso cuando se acaba su quantum. Todos los procesos en ready tienen la
misma prioridad.
Colas multinivel
Con estas colas se tienen diferentes colas de ready para procesos batch y para procesos interactivos, a las
cuales se le asocia un porcentaje de uso de la CPU.
Hay colas multinivel realimentadas, en estas colas los procesos entran en una cola donde se asigna un
quantum, si no tiene suficiente quantum, el proceso pasa a otra cola con un quantum mayor.
En estas colas multinivel realimentadas, se ejecutan los procesos de la cola que asigna menor quantum, en la
última cola habría un algoritmo de planificación FCFS.
Ejemplo: UNIX
Diagrama de estados en UNIX.
User runnig: ejecutando código de usuario.
Kernel runnig: ejecutando código de sistema (llamadas al sistemas, servicio a las interrupciones, etc.).
Preempted: se ha sacado un proceso de la CPU, porque se ha acabado el quantum o aparece un proceso mas
8
prioritario que el que se estaba ejecutando.
El algoritmo de planificación que utiliza es el Round−Robi con colas multinivel autoalimentdas. Unix
distingue entre procesos expulsados y procesos bloqueados. Si un proceso se ha expulsado va a la parte de
arriba de una pila de prioridades, donde hay menos prioridad, y no podrá bajar del umbral, a partir del cual de
guardan los procesos que se han bloqueado voluntariamente. La parte de arriba de dicha pila esta
realimentada, es decir, cuando un proceso de esta parte pasa a ejecutarse, los que están por encima
descienden.
TEMA 3: MECANISMOS DE ENTRADA EN EL S.O.
Introducción
Aquí veremos como una llamada al sistema entra en el sistema operativo (entra a ejecutar código del S.O.).
Hay tres métodos de acceso:
• Interrupciones: creadas por el hardware de dispositivos externos y que se producen de forma
asíncrona. Estas se miran siempre después de ejecutar una instrucciones máquina.
• Excepciones: interrupciones creadas de forma involuntaria en el proceso (fallo de pagina, división por
cero, overflow, etc.). Hay excepciones que destruyen el proceso y otras que después de ejecutar un
código vuelve al proceso como el fallo de página. Una excepción se mira entre microinstrucciones
(fetch del operando 1, fetch del operando 2, etc.).
• Traps: mediante llamadas al sistema. Un trap es una interrupción software provocada por la
instrucción de lenguaje máquina INT.
Llamadas al sistema
Las llamadas tendrán que salvar el contexto del proceso, cambiar a modo privilegiado (este cambio se hace
por hardware y es el modo en el cual se puede ejecutar código del sistema, nosotros simularemos el cambio
por software), restaurar al modo usuario y por último restaurar el contexto.
Desde el proceso de usuario se puede hacer la llamada a la librería interna del S.O. pero deberíamos saber:
• El trap de la llamada al sistema.
• Como se hace el paso de parámetros.
• Como se devuelve el resultado.
Pero con las librerías del S.O. no hace falta que sepamos estos tres puntos. Se puede hacer una llamada pero
gracias a las librerías del S.O. La librería del S.O. es quién ejecuta el trap correspondiente a la acción que
pedimos.
Hacemos que todas las llamadas al sistema generen la misma interrupción software, ya que no hay espacio en
el vector de interrupción para guardar las direcciones de todas las rutinas de servicio (la interrupción que
utilizaremos será la 64).
En el vector de interrupciones tenemos guardada la rutina intermedia (Trap()) que comprobará que llamada se
ha ejecutado y ha provocada la interrupción, una vez hecha esta comprobación se ejecutará la rutina interna
adecuada a la llamada al sistema. Para comprobar que llamada se ha ejecutado se utilizan los registros de la
CPU, en ONION utilizaremos el registro AX del proceso que ha hecho la llamada, ahora cada llamada moverá
al AX un código que indicará que llamada ha ejecutado el trap.
Paso de parámetros
9
Los parámetros se introducen de forma inversa a como se han escrito en la pila, una vez pasados los
parámetros se pasa la dirección de retorno. Al producirse un trap se guardan los flags y la dirección de retorno
a la librería del S.O., donde se produjo la interrupción. La rutina TRAP salvará el contexto del proceso que se
estaba ejecutando, mira el contenido del registro AX y ejecuta la rutina interna del S.O. correspondiente al
código que contenía el registro AX.
El acceso a los parámetros se realiza en la pila pero no encima del la última dirección de retorno sino al
principio de la pila. Para solucionar esto, se pueden tener dos pilas, una pila del usuario y la pila del sistema
que tendrá copias de los parámetros del usuario, esta es la mejor forma. También se podría reestructurar la pila
para que los parámetros estén después de la última dirección de retorno, pero, en este caso, también se debería
reestructurar por segunda vez, para dejar la pila como estaba. Pero nosotros declararemos un parámetros que
tendrá la longitud desde la última dirección de retorno hasta los parámetros, este parámetro será un struct
llamado dummy.
Struct dummy
{
int p[16];
}
Resultados
Cuando termina la ejecución de la llamada volvemos a la dirección de retorno 3, restauramos el contexto, y se
vuelve al lugar donde se produjo la interrupción, y por último se sacan los parámetros de la pila.
La llamada al sistema normalmente devuelven un entero, este resultado se devuelve en el registro AX, si es un
carácter o un entero, o con el DX y AX si el resultado es un long o un far pointer. Todos devuelven en AX el
resultado, pero en la rutina TRAP se hace un restaurar y por lo tanto el contenido de AX se podría perder con
el contenido de la pila. Para devolver correctamente el resultado se debería:
• Acceder a la posición de la pila correspondiente a AX e introducir el resultado dentro de la llamada al
sistema.
sci (dummy, par1, par2)
{.
*(run−>sssp+3)=res;
.
}
• O en la rutina de TRAP hacer que devuelva un resultado que se almacena en la pila.
TRAP()
{.
*(run−>sssp+3)=sci();
10
.
}
• O utilizar el parámetro dummy donde se introducirá el resultado.
Typedef struct
{ int bp, es, ...
} dummy;
dins de la rutina interna: dummy.ax=res.
Niveles de interrupción
Ejecutando código de las rutinas de servicio a las interrupciones, ejecutando el TRAP o el código de la
llamada, las interrupciones están inhibidas y por tanto no nos llega ninguna interrupción.
Ejecutando una llamada de sistema, haremos un desinhibir interrupciones y así nos llegan interrupciones
hardware (desinhibir(0x200)).
Al poder llegar interrupciones hardware el puntero sssp podría ser que nos apuntara a la segunda vez que se ha
salvado el contexto producido por una interrupción y al hacer el restaurar del TRAP podría ser que no se
restaurara bien ya que sssp apunta a otra posición (final de la segunda salvación del contexto). Por tanto
tendremos dos niveles de interrupciones y por tanto podríamos tener dos apuntadores de pila sssp[0] que
apunte a la primera vez que salvamos y sssp[1] que apunte a la segunda vez que salvamos. Para implementar
esto necesitaremos otro campo que indica en que nivel nos encontramos:
• Modo 0= interrupción cuando se ejecuta código de usuario.
• Modo 1= interrupción cuando se ejecuta TRAP o una llamada al sistema. O ejecutando una RSI si
venimos de interrumpir código de usuario.
• Modo 2= ejecutando una RSI si venimos de interrumpir el código de sistema.
Struct pcb{
.
int *sssp[2];
int modo;
}
Salvar = run−>sssp[run−>modo]=salvar();
run −> modo++;
Restaurar = run −> modo−−;
Restaurar(run−>sssp[run−>modo]);
11
TEMA 4: SISTEMA DE FICHEROS
Visión Estática
Los soportes físicos están estructurados en bloques. Existen bloques libres y ocupados por el fichero.
Gestión de bloques libres
Existen diversas formas de gestión:
Gestión con un mapa de bits donde 0 indica que el bloques está libre i 1 si está ocupado. Necesitamos un
espacio fijo para esta gestión (para guardar el mapa de bits).
También existe la lista de bloques libres. Esta lista puede estar encadenada donde los lugares libres se
encadenan entre ellos.
La lista encadenada tiene el defecto que si tenemos N bloques libres necesitaremos N lecturas para encadenar
estos lugares libres.
Otra versión de las listas es la que consiste en el agrupamiento (listas de agrupamiento). En esta versión se
guarda en el primer bloque libre la lista de todos los bloques libres. Si en un bloque no cogen todos los
punteros de las posiciones libres, se utilizaría otro bloque, pero donde el último elemento del primer bloque
incidiría el bloque siguiente donde se sigue guardando la información (lugares libres).
La última versión consiste en el recuento, donde se introduce en un bloque el número de bloques libres
consecutivos que le siguen.
Gestión del espacio ocupado
Asignación contigua: obligamos a que todos los ficheros tengan todos loa bloques en forma contigua dentro
del disco, esto permite acceso secuencial y acceso directo.
Esta asignación es problemática por la asignación de espacio al fichero, ya que crea fragmentación externa
(existe lugar libre pero no hay los suficientes bloques consecutivos para insertar un fichero).
Existen 3 métodos para asignar espacio:
• First Fit: primer espacio libre en el que coja el fichero.
• Best Fit: buscamos el espacio libre que mas se ajusta a nuestro fichero.
• Worst Fit: se coloca en el peor espacio, así en el espacio libre que queda pueda coger otro fichero.
Asignación encadenada/enlazada: los bloques de los ficheros están encadenados (al igual que con las listas
encadenadas de los espacios libres). Ahora no se produce fragmentación externa (se puede insertar en
cualquier bloque) y por lo tanto no existen problemas de asignación de espacio.
Pero ahora el acceso solo se podrá realizar de una forma: de forma secuencial ya que no sabemos donde está
el bloque i−esimo de u fichero y se tendría que recorrer todos los bloques encadenados. Necesitamos por lo
tanto un puntero para hacer la encadenación y estos se pueden perder si se cae el sistema.
Un caso particular seria la FAT del DOS (File Allocation Table). Esta tabla tiene en la posición i la
información del bloque i (la dirección del siguiente bloque del fichero, estado del bloque y si es el final del
fichero −eof−). Esta FAT debería estar en memoria ya que si no esta deberíamos acceder siempre primero al
12
disco. Con la FAT aún tenemos el acceso secuencial ya que se recorrería la FAT en busca del bloque deseado.
Por lo tanto el mayor problema es que la FAT no nos cogiera en memoria, y por lo tanto no tendría ninguna
ventaja. La FAT es más grande conforme más grande sea la capacidad del disco. Si no nos cogiera la FAT
podríamos dividir el disco en cluster y no en bloques, donde un cluster tendría 1, 2 o 4 bloques (siempre
múltiple de dos), así cada entrada a la FAT representa un cluster (que será la unidad de asignación de
espacio).
La unidad de asignación de espacio es la cantidad de memoria que se le asigna a un fichero cuando necesita
mas espacio y lo que se libera cuando el fichero no necesita ese espacio.
La unidad de transferencia es la cantidad de información que se puede transportar de disco a RAM, esta
cantidad es de 1 sector (1 bloque).
Otra solución es el volume, que consiste en dividir el disco en particiones donde cada una tiene su propio
sistema de ficheros, así se reduce el espacio de FAT ya que cada partición tiene su propia FAT.
Para acceder a los ficheros necesitamos el fichero directorio, el cual tiene información sobre otros ficheros
(nombre, número de bloques que ocupa en disco). Este directorio en asignación contigua contiene la posición
del primer bloque del fichero. Y en asignación encadenada contiene la posición del primer bloque del fichero,
pero para acceder, por ejemplo, al tercer bloque se debería pasar por la entrada que indique el directorio
referente a ese fichero, después por la siguiente hasta de la FAT hasta que se llega al bloque deseado. Si
deseamos el primer bloque, o los ficheros ocupan un solo bloque, entonces no hace falta pasar a la FAT ya
que el directorio contiene el primer bloque de los ficheros.
En cada partición se tiene un superbloque que indica donde se encuentra la FAT, donde se encuentra el
directorio raíz, etc.
Asignación indexada: ahora tenemos un bloque por fichero (bloque índice). En este bloque índice tendremos
la dirección de los bloques que pertenecen al fichero. Para ficheros muy pequeños necesitaremos un bloque
índice pero donde se utilizarán muy pocas entradas.
Ahora cada fichero ocupará n+1 bloques. Si los índices de los bloques no cogen en el bloque índice se pueden
tener diferentes bloques índices encadenados o bien tener diferentes niveles de bloques de índice.
Con esta asignación se puede tener acceso directo pero siempre se ha de pasar por los diferentes bloques
índices que tenga el archivo.
Un caso particular son los Inodes de UNIX. Cada fichero tiene un inode que contiene la información de los
ficheros, dentro de cada inode hay 10 apuntadores directos a bloques del fichero. Si con los 10 apuntadores no
tenemos suficientes para representar el archivo, se crearía un apuntador indirecto (apuntador a un bloque de
índice donde caven aproximadamente 256 apuntadores a bloques de datos), si todavía no tuviéramos
suficientes apuntadores se crea un apuntador doblemente indirecto (este apunta a un bloque y las posiciones
de este bloque apuntan a otros bloques de índices), y si todavía no tenemos suficientes se pueden crear
apuntadores triplemente indirectos (donde cada puntero del bloque apuntado por cada puntero directo, apunta
a otros bloques y las posiciones de estos a bloques de índices).
Con inodes en el directorio solo tendremos el nombre del fichero y el número de inode. Así pues existe una
tabla de inodes, indexada por el número de inode, donde está toda la información de los ficheros (nombre del
dueño, protecciones, etc.).
Ahora para acceder al directorio raíz, tenemos que pasar por el inode en lugar de por el superbloque. Cada
inode está en el disco y ocupa 1 bloque de espacio. Por lo tanto para acceder al tercer bloque de un fichero
13
tendríamos que:
• Obtener el inode raíz del disco.
• Obtener el directorio raíz a partir del inode raíz.
• Obtener el inode j correspondiente al directorio donde se encuentre el fichero.
• Obtener el directorio correspondiente.
• Obtener el inode k correspondiente al fichero deseado.
• Acceder al tercer bloque.
Compartición de ficheros
Cualquier modificación se podrá ver por otras vías si el fichero está siendo compartido. Hay dos formas de
compartir ficheros:
Hard link: entrada de directorio que apunta al fichero el cual queremos compartir. Por lo tanto apuntan al
mismo inode en el caso de UNIX.
En MS−DOS no se puede compartir ficheros ya que al modificar un fichero se modifica la información de la
entrada al directorio, pero si estuviera compartido otra entrada de directorio tendría la información antigua que
ya no sería válida.
Soft link: creamos un fichero que contendrá el camino de acceso al fichero compartido (pathname). El
pathname puede ser absoluto, dando la dirección des del directorio raíz, o puede ser relativo si se da la
dirección a partir del directorio de trabajo. En este caso se crea un inode diferente ya que se crea un nuevo
fichero, aunque contenga solo la dirección de otro fichero.
Directorios
Los directorios son ficheros con una estructura interna especial donde guardan la dirección de todos los
ficheros que contiene dicho directorio. Cada directorio tiene su propio inode.
Sistema de ficheros (S.F.)
Hay diferentes sistemas de ficheros:
• 1 nivel: un directorio raíz, donde se encuentran todos los ficheros del ordenador. El directorio tendrá
tantas entradas como ficheros diferentes tenga. Todos los nombres de los ficheros tienen que ser
diferentes.
• 2 niveles: un directorio raíz, donde se encuentran los directorios/usuarios que corresponden, uno a
cada usuario. Pero todos los ficheros de cada directorio/usuario tienen que ser diferentes en cada
directorio.
• Jerárquico: (DOS) un directorio raíz a partir del cual se pueden colgar diferentes ficheros y
directorios. Para cada fichero se tiene su pathname (absoluto si se especifica a partir del directorio raíz
o relativo si se especifica a partir del directorio de trabajo). No se pueden compartir ficheros, ya que
solo existe un camino para cada fichero.
• En grafos: acíclicos (Unix) son los que no permiten bucles, es decir, que no permiten que un
directorio llame a otro directorio superior a él. Permiten compartir ficheros y por lo tanto se puede
acceder a un fichero por diferentes caminos.
Cíclicos o general permiten los bucles dentro del sistema de ficheros donde un directorio puede apuntar a un
directorio anterior a él
14
Ejemplos
1 nivel
CP/m.
Jerárquico
DOS: no permite hard link. Entrada de directorio.
Bytes
8
3
1 10
2
2
2
15
Descargar