Introducción a Sistemas Operativos y Hardware
Introducción a Sistemas Operativos y Hardware
Sistemas Operativos
1
Lucila Canalini
03/04/2020
Introducción al Hardware
El procesador está compuesto por: registros, la unidad aritmética lógica (UAL), la cache, etc.
Registros visibles: Son los que el usuario puede manipular de manera directa.
Registros de control y estado: Suelen ser registros que nos permiten administrar y
mantener un buen mantenimiento del computador.
Ciclo de instrucción
Una vez que una instrucción empieza a ejecutarse, no puede interrumpirse hasta el final. Los
pasos que se ejecutan dentro de una instrucción son: fetch, decode, execute.
Si tenemos un procesador podemos ejecutar un solo programa a la vez.
Para poder ejecutar un conjunto de instrucciones, una computadora debe cargar las
instrucciones del disco (I/O) solamente a memoria.
Interrupciones
Una interrupción es un mecanismo que tienen los dispositivos de hardware para cortar el flujo
de instrucción de un programa. Así, una vez atendida, implica siempre un cambio a modo
kernel, pero el programa que se estaba ejecutando y se interrumpió, no se entera de que fue
interrumpido.
2
Lucila Canalini
Se utilizan para cortar la ejecución de la secuencia actual de instrucciones para que el SO pueda
seguir haciendo cosas. Nos ayuda a hacer las cosas en “paralelo” aunque realmente no es así.
Son notificaciones de eventos dirigidas al procesador. Cualquier dispositivo de E/S puede
enviar interrupciones al procesador para que detenga lo que está haciendo y se ponga a hacer
otra cosa. Siempre estas notificaciones tienen de destino final el procesador.
Para atender una interrupción, es necesario, previamente guardar el estado de todos los
registros del procesador.
Después de ejecutar cada instrucción, antes de pasar a la siguiente, pregunta por un flag si hubo
alguna interrupción, y en caso positivo, se la atiende. Esto es porque una vez que se ejecuta la
instrucción, esta no se puede interrumpir mientras se está ejecutando.
Se pueden clasificar de varias maneras dependiendo de quien lo origino:
Hardware (externas al procesador): Las que vienen de un dispositivo de E/S.
Por ejemplo: Un disco, una posición de memoria que se rompió.
Software (internas al procesador): Se originan dentro del procesador como
consecuencia de la ejecución de una instrucción.
Por ejemplo: Hacer una división por 0.
Enmascarables: Pueden no ser ejecutadas en el mismo instante.
Por ejemplo: Una lectura de disco, pero la computadora está haciendo algo más
importante, se puede postergar.
No enmascarables: Se tienen que atender siempre.
Por ejemplo: Una falla de hardware no se puede pasar por alto (falla eléctrica, de
memoria, etc.), no puede postergarse.
E/S.
Fallas de Hardware: Falla cuando no se encuentre un dispositivo, por lo que no se
pueda usar.
Clock: Reloj de la computadora. Dispositivo Hardware que nos interrumpe cada cierto
tiempo que podemos definir como sistema operativo.
3
Lucila Canalini
La interrupción se atiende siempre que se termina una ejecución. Luego de cada ciclo de
instrucción se valida si es que hay interrupciones por lo que se atenderá al finalizar de ejecutar
la instrucción en curso. Luego de atender la interrupción seguirá con la syscall.
4
Lucila Canalini
Técnicas de entrada/salida
E/S programada.
E/S por interrupciones.
Acceso directo a memoria (DMA).
Jerarquía de memoria
Cuando hablemos de memoria nos referimos a la memoria RAM, pero todas las memorias
tienen tamaños y velocidades diferentes, aunque las utilizamos para tener un sistema de
memoria acorde al que necesitamos.
Memoria interna de la computadora:
Registros de CPU: La que se encuentra más cerca del procesador.
Memoria Cache.
Memoria RAM.
Memoria secundaria:
Disco de estado sólido.
Disco magnético.
Almacenamiento terciario:
Discos ópticos CD/DVD
Almacenamiento fuera de línea (cintas): La que se encuentra más lejos del procesador.
Mientras más lejos se encuentre del CPU, mayor tamaño tiene, pero menor costo y más lento.
5
Lucila Canalini
Modos de ejecución
Separar en dos modos aumenta la seguridad, evitando que el usuario ejecute instrucciones
privilegiadas que puedan dañar al sistema. El procesador va cambiando de modo usuario a
modo kernel constantemente.
Modo kernel es el sistema operativo: Puede ejecutar instrucciones privilegiadas y no
privilegiadas.
Modo usuario es todo lo que no sea el sistema operativo: El Word, el Chrome, el block de notas,
etc. Solo puede ejecutar instrucciones no privilegiadas.
Motivos para que haya cambio de modo:
Son las interrupciones (se está ejecutando una instrucción en modo usuario, se realiza la
interrupción en modo kernel, y luego vuelve a modo usuario para que pueda seguir ejecutando
sus programas de usuario), y las llamadas al sistema (mecanismo que ofrece el SO para que
los programas o programadores puedan pedir algún servicio al Sistema Operativo).
Si un usuario, un programador, necesita hacer algo que implique una instrucción privilegiada,
debe hacerlo a través de una Syscall.
6
Lucila Canalini
llamada al sistema, se cambia a modo kernel, y solamente en dicho modo se pueden ejecutar
instrucciones privilegiadas.
Suelen ser utilizadas a través de una API por medio de wrappers. Estas son funciones que
incluyen alguna llamada al sistema. Un programa escrito utilizando wrappers de una biblioteca
standard permite portabilidad.
La syscall es el punto de entrada oficial y último para solicitar un servicio al sistema operativo.
Ofrece máxima flexibilidad de uso y optimizaciones de performance, aunque carece de
facilidad/claridad/portabilidad de uso.
El wrapper (de una syscall) es una función que corre en modo usuario que se interpone entre
la solicitud del servicio y la syscall real. Ofrece mayor facilidad/claridad/portabilidad en el uso,
aunque restringe flexibilidad y la posibilidad de realizar optimizaciones de performance.
14/04/2020
Programa
Un programa es una secuencia de instrucciones compiladas a código máquina. Esto significa
que escribimos nuestros programas en un lenguaje de programación, lo compilamos y genera
un archivo binario (ejecutable) donde encontramos las instrucciones que debe seguir el
programa. Es un archivo dentro de la computadora que si nunca lo abriste seguro nunca lo
necesitaste.
7
Lucila Canalini
Procesos
Un proceso es mucho más que un programa que se está ejecutando. Es una secuencia de
instrucciones (un programa) que contiene el programa y más componentes asociados al
proceso y la memoria que utiliza. Un proceso tiene vida y está todo el tiempo haciendo algo. El
Sistema Operativo trabaja con procesos.
8
Lucila Canalini
datos estáticos
pila
heap
Estos son espacios de memoria utilizados para que el
programador guarde datos (Arrays, Variables, etc.). El código
del programa no puede modificarse y el PCB solo lo manipula
el Sistema Operativo.
Ciclos de vida de un proceso (esto es desde que inicia hasta que termina)
Sobre los estados:
Un proceso está Listo cuando está esperando para ser pasado al procesador y poder ejecutar
sus instrucciones.
9
Lucila Canalini
El estado Suspendido sirve para un proceso que está siendo depurado. Uno de los usos de este
estado es para la depuración de procesos. Otro uso es para aquellos procesos que pasan de
Memoria Principal al Área de Intercambio (o Swapping).
El proceso en estado Finalizado, aunque no conserva el código, los datos, la pila y el heap,
mantiene el PCB, por lo tanto, sigue existiendo. Se mantiene por fines estadísticos o porque
ningún proceso tomó su valor de retorno. Su padre pudo haber finalizado, pero el proceso
puede seguir ejecutando.
Esto no va a ser siempre así. En algún momento de tiempo puede ser que el PCB3 pase a “No
ejecutado” para que el PCB4 pase a ejecutar. Los procesos constantemente pueden pasar de un
estado a otro. Los PCBs están enlazados entre sí, al azar, o quizás no, pero todos tienen una
prioridad para ejecutarse antes que otro.
Para que funcione bien tiene que tener los estados listos, bloqueado, y ejecutando, por lo que
el diagrama de 2 estados no funciona muy bien.
Estado de los procesos: Diagrama de 3 estados.
En este diagrama, un proceso que no está listo es uno que está bloqueado. Se bloquea porque
seguramente hubo una llamada al sistema. No podrá seguir ejecutando hasta que no obtenga
lo que pidió. Un ejemplo sería si solicitó abrir un archivo para adquirir información. Hasta no
obtenerla, estará bloqueado.
Para que un proceso ejecutando pase a bloqueado puede ser una llamada al sistema porque
necesita algo del Sistema Operativo o, raramente, porque el proceso quiere dejar de ejecutar
porque prefiere que ejecute otro o decide hacer otras cosas.
Un proceso bloqueado puede pasar a listo cuando obtiene lo que se le solicitó al Sistema
Operativo. Se entera que obtuvo dicha información a través de una interrupción. Esta
interrupción nos dirá que la lectura del disco, o lo que se necesitaba hacer, ya finalizó. Cuando
10
Lucila Canalini
El estado finalizado es cuando el PCB se queda aguardado para ver qué valor se retorna. El
lugar que ocupaba en memoria y datos globales se liberan. Solo conserva su PCB, el resto lo
elimina para no seguir ocupando espacio. Cuando otro proceso toma el valor de retorno de
dicho proceso, sale del sistema y deja de existir.
Estado de los procesos: Diagrama de 7 estados.
11
Lucila Canalini
Creación de un proceso
Puede ser creado por el sistema operativo para dar algún servicio. Yo creo un proceso porque
necesito que haga algo para mí.
También puede ser creado a pedido de otro proceso. El proceso que crea otro proceso se
llamará padre y el creado se llamará hijo. El proceso padre e hijo pueden ejecutar de forma
concurrente o el padre puede esperar a que los hijos finalicen.
12
Lucila Canalini
Finalización de un proceso
a) Terminación normal, donde se ejecuta la llamada al sistema exit. No la escribimos
cuando programamos, pero cuando hacemos return el programa sabe que es un exit. El
valor de retorno es el exit_status que es lo que le ponemos al return. También hay un
caso wait, en el que hay que esperar que termine el hijo.
b) Terminado por falla o condición de error, como lo sería una división por cero.
c) Terminado por otro proceso. El comando kill envía señales, entre ellas, una puede ser
matar a un proceso. Desde la consola puedo hacer kill, algún código que indique la
eliminación de un proceso, y el número de proceso.
Cambio de un proceso
Un proceso ejecuta sus instrucciones y, en algún momento, por alguna razón, el Sistema
Operativo toma el control del procesador y comienza a administrar los procesos y los recursos.
Cuando paso del proceso al Sistema Operativo hubo un cambio de modo: estaba ejecutando en
modo usuario y ahora que está en el Sistema Operativo está en modo kernel.
El Sistema Operativo hace sus tareas, puede estar atendiendo una interrupción, una llamada al
sistema, etc. Cuando termina, vuelve a ejecutar el proceso que estaba ejecutando. Nuevamente,
hay un cambio a modo usuario.
Vuelve a aparecer una llamada al sistema o interrupción y aparece el Sistema Operativo. Ahora,
el SO decide que se siga con el siguiente proceso cuando termina de hacer sus tareas, en lugar
de volver al proceso que todavía no estaba terminado de ejecutar. A esto le llamamos cambio
de proceso. Lo que paso previamente de que paso del primer proceso al Sistema Operativo y de
nuevo al proceso inicial, no fue un cambio de proceso.
13
Lucila Canalini
Un process switch implica dos cambios de modo. Puede generarse por una interrupción o por
una llamada al sistema. El primer cambio de modo es de modo usuario a modo kernel, y el
segundo es de modo kernel a modo usuario.
Overhead (sobrecarga): Son las tareas administrativas que lleva a cabo el sistema operativo.
Son tareas que a mí como usuario no me interesa que se hagan, aunque es importante que se
hagan porque permite que se ejecuten varios programas a la vez, etc.
Pasos del cambio de proceso (podrían ser más):
1. Ejecutando Proceso A, se produce una INTERRUPCIÓN.
2. Se guarda el PC y PSW del proceso A.
3. Se actualiza PC para atender la interrupción y se cambia de modo de ejecución (modo
usuario a kernel).
4. Se guarda el resto del contexto del proceso A.
5. Se decide cambiar el proceso.
6. Se guarda el contexto del proceso A en su PCB.
7. Se cambia el estado del proceso A de Ejecutando a Listo (u otro).
8. El PCB del proceso A se ubica en la lista de procesos Listos (u otra).
9. Se selecciona otro proceso para ser ejecutado (el proceso B).
10. Se cambia el estado del proceso B a Ejecutando.
11. Se actualizan los registros de administración de memoria del procesador con los del
proceso B.
12. Se actualizan los registros del procesador con los del PCB de B y se cambia el modo de
ejecución (modo kernel a usuario).
En el PCB se guardarán los registros del procesador cuando el proceso no esté en estado
Ejecutando. Esto es porque cuando lo esté, no es necesario guardar los registros en el PCB ya
que los está utilizando y estos varían constantemente.
18/04/2020
Hilos
Son subprocesos que permite que se hagan varias cosas a la vez. Nos da ventajas con respecto
a los procesos. Los hilos en ejecución comparten las variables globales (Datos) y la memoria
dinámica (Heap). A través de una variable global podría accederse a la memoria dinámica.
Dos hilos de diferentes procesos pueden ejecutar secciones de código idénticas entre sí. Datos,
Pila y Heap, son espacios de memoria utilizados para que el programador guarde datos (Arrays,
Variables, etc). El código del programa no puede modificarse y el PCB sólo lo manipula el
Sistema Operativo.
Monohilo
Un proceso que tiene un solo hilo de ejecución. Tenemos una secuencia de instrucciones y
vamos haciendo una por una y siempre una después de la otra, salvo que haya algún salto. Una
serie de pasos a seguir, como si fuese una receta. No tenemos manera de hacer varias cosas a la
vez. Es un program counter saltando de una instrucción a la otra.
14
Lucila Canalini
Multihilo
Hace muchos años no se usan los sistemas monohilo, porque ahora existe la posibilidad de
hacer sistemas multihilo. Su función es poder aprovechar recursos y poder hacer muchas cosas
al mismo tiempo en un mismo programa. Esto surge porque el contexto de ejecución del
programa está separado de los recursos que utiliza un proceso. Si hay un solo procesador, hay
un solo proceso ejecutando, y se está haciendo una única cosa a la vez. No es ventajoso si
buscamos seguridad, pero tiene varias ventajas:
Capacidad de respuesta: Un proceso aprovecha mucho mejor el procesador por más
que esté a la espera de información. Procesamiento simultaneo de un mismo proceso
(no en paralelo).
Economía: Se refiere a la economía del Sistema Operativo. Ahorro recursos y hacer
cambios entre hilos también será rápido. No habrá tanto overhead.
Compartición de recursos: Porque un hilo puede abrir un archivo, y el resto de los
hilos también. Se logra compartir recursos al compartir variables.
Comunicación eficiente: Compartir recursos es una de las maneras que tienen los
procesos de comunicarse, mandándose paquetes, por ejemplo.
Permite multiprocesamiento.
Procesamiento asíncrono: Ningún hilo tiene que esperar que otro hilo haga algo para
poder ejecutar.
El procesador va a ejecutar siempre lo mismo, a la misma velocidad que puede, pero tiene la
ventaja de que hoy en día los procesadores tienen varios núcleos, por lo que cuando salte entre
diferentes hilos va a ser mucho más rápido que si cambio entre procesos. Va a ser más rápido
desde el punto de vista del proceso, pero desde la vista del procesador, va a ser la misma
cantidad de tarea. Su velocidad es fija para todo.
En un sistema operativo que admite procesos multihilo, cambian la pila y el PCB por ser parte
del contexto de ejecución del programa. Cada hilo tiene su propio contexto, sus propios datos
particulares y su propio estado. El PCB se dividirá en dos: una pila y un TCB. Así es como el
proceso contiene una pila por cada hilo. Por otro lado, el código, los datos y el heap son
compartidos por todos los hilos del mismo proceso.
Los procesos con múltiples hilos requieren un PCB y un TCB por cada hilo. El PCB guarda la
información relacionada al proceso. Cada hilo tiene su propio TCB, con información relacionada
a ese hilo. Los hilos, independientemente de que sean KLTs o ULTs comparten memoria (por
ejemplo, variables globales) sin intervención del sistema operativo.
15
Lucila Canalini
16
Lucila Canalini
Portabilidad: Como no hago llamadas al SO, con solo darle soporte a mi programa, yo
podría llevarme el programa y ejecutarlo en otra plataforma. No hay dependencia de
creación y comunicación de hilos con el SO, sino que la biblioteca es la que provee.
E/S bloqueantes
En el caso de los programas que implementan hilos de usuario,
tenemos el problema de que, si voy a esperar en la red o leer un
archivo, me va a bloquear todo el proceso hasta que dicho recurso
que necesitaba esté disponible y el Sistema Operativo se lo provea
al proceso para consumir. Hay métodos en los cuales podríamos
utilizar E/S bloqueantes y no bloqueantes.
Si convierto la llamada bloqueante en no bloqueante, puedo lograr
que el proceso no se bloquee nunca o al menos intente no
bloquearse cada vez que tenga que hacer una syscall. Para lograr
utilizar los ULT en muchas bibliotecas se utiliza el jacketing.
Jacketing
Previene que un hilo ULT se bloquee en caso que el dispositivo este
bloqueado. Convierte una E/S bloqueante en una no bloqueante.
Como el Sistema Operativo desconoce la existencia de los hilos ULT
y sólo conoce a la entidad proceso, el sistema operativo bloquea al
proceso completo. Si los hilos ULT utilizaran la técnica de Jacketing,
el proceso no se bloquearía. Además, los hilos no cambiarían de
estado porque cada uno tiene su propio contexto de ejecución.
Algunos podrían estar bloqueados o listos.
17
Lucila Canalini
Cada hilo de kernel se va a comportar como un proceso para el sistema operativo. El sistema
operativo lo va a ver y por eso podrá planificarlo y asignarle recursos dentro del procesador.
Syscall bloqueante bloquea solo ese hilo: Si algún hilo de kernel pide una llamada
bloqueante, se bloqueará únicamente este hilo, el resto de los hilos podrían
tranquilamente funcionar. Básicamente, no bloquea el proceso, sino que bloquea
únicamente el KLT.
Permite multiprocesamiento de hilos del mismo proceso: Cada hilo de kernel tiene
su propio PC por lo tanto tengo soporte de estructuras que el procesador puede
manejar. Los hilos KLT de un mismo proceso pueden ejecutar en diferentes
procesadores. Si bien forman parte de un mismo proceso, el sistema operativo los
gestiona como procesos diferentes.
Mayor overhead respecto ULT: Esto es porque cualquier cosa que se quiera hacer con
los hilos deberá pasar por el sistema operativo porque este los planifica.
Planificación del sistema operativo: Si el SO puede ver los hilos de kernel, los va a
poder planificar, y esto significa que vamos a estar atados al sistema operativo y su
planificación. Si tiene una planificación que no es afín a lo que necesitamos, traerá
problemas, pérdidas de tiempo, etc.
1. Se guarda una parte inicial del contexto (PC, FLAGS) en el stack del sistema.
2. El SO ingresa su ejecución y guarda el resto de los registros en el stack del sistema.
3. El SO determina que debe realizar un thread switch.
4. Mueve el contexto de ejecución completo del stack del sistema al TCB del hilo.
5. Elige el próximo hilo a ejecutar.
6. Copia todo el contexto del TCB del nuevo hilo al procesador y realiza un cambio de modo
(a usuario), todo al mismo tiempo.
18
Lucila Canalini
24/04/2020
Planificación de CPU
La planificación de un proceso es información que se
guarda en el PCB.
Cuando cambiamos de proceso, una de las tareas que hay
que hacer es elegir qué proceso se va a ejecutar ahora.
Podría ser elegir un proceso al azar, pero no es lo más
conveniente.
Uno de los recursos masmás importantes q tiene el
sistema es el procesador, porque es el recurso que si o si
van a utilizar los procesos.
La idea de la planificación del CPU, es asignar el próximo
proceso y el motivo por el que se elijeelige dicho proceso.
La idea es queque, si tengo muchos procesos en el
sistema, todos los procesos puedan ejecutar un poco, y que ningún proceso se quede sin
ejecutar en absoluto.
Muchas veces el proceso que tenemos que elegir para que siga ejecuandoejecutando es porqueq
tenemos un sistema que funcione para algo en particular.
Hay muchos tipos de procesos: los del sistema, los interactivos con los usuarios, sistemas que
ejecutan procesos uno después del otro sin tener interacción con el usuario.
Objetivo:
Asignar procesos al procesador.
Rendimiento / Productividad.
Optimizar algún aspecto del comportamiento del sistema.
Ciclo de ráfagas
Empieza usando el CPU, entrada/salida, CPU, entrada/salida, constantemente. Es la forma
normal que tienen los procesos de funcionar.
Procesos limitados por la CPU: En estos, las ráfagas de CPU, que son todas las instrucciones
que se ejecutan simultáneamente, son muchas más que las que ejecuta de entrada y salida.
Procesos limitados por la E/S: Lo contrario a los otros. Tienen poco de CPU y mucha espera
de E/S. Después otra vez poco CPU, y así. Un ejemplo es algún programa interactivo, en la que
el sistema espera a que nosotros hagamos algo.
19
Lucila Canalini
En los planificadores de largo y medio plazo pueden afectar el orden de los procesos en lista
de procesos listos para ejecutar.
Los nombres de las planificaciones tienen que ver con cada cuanto se llevan a cabo. Las de largo
plazo son porque solamente se hacen cuando llega o se va un proceso, lo que no pasa tan
seguido como lo que pasa en la planificación de corto plazo.
1. Planificador de largo plazo: Involucra los estados New y Exit. Ambos estados tienen
un grado de multiprogramacion que indica cuantos procesos puedo tener en el sistema
ejecutando como maximo en un intervalo de tiempo. Cuando un proceso finaliza, hay
lugar para un proceso nuevo. El grado de multiprogramación se modifica cuando pasa
esto. El planificador de largo plazo, al momento de admitir un proceso nuevo, puede
afectar el orden de los procesos de Listos.
20
Lucila Canalini
Decide cuál es el próximo proceso quese debe ejecutar, según el objetivo del sistema operativo,
conviene elegir uno u otro. También decide dónde ubicar el PCB del proceso que se estaba
ejecutando.
La interrupción de Clock permite que el SO, tome el control del procesador para que realice
alguna tarea. Esa tarea puede ser realizar un cambio de proceso, o no. El procesador no realiza
cambios de proceso.
21
Lucila Canalini
Criterios de planificación
Son los que nos permiten tomar una decisión sobre qué tipo de proceso elegir en cada momento.
Los criterios pueden ser:
Orientados al usuario: Cómo ve el usuario el funcionamiento de los procesos.
Orientados al sistema: Es un análisis general de como funciona el sistema operativo.
Las métricas nos dan un valor preciso pero no podemos optimizar todas a la vez. Por ejemplo,
el tiempo de espera está en contra de la utilización del CPU.
22
Lucila Canalini
Algoritmos de planificación
A cada proceso se le asigna una prioridad. La prioridad de un proceso puede cambiar a lo largo
de todo su cilco de vida. La idea es que el planificador seleccione el proceso de prioridad más
alta.
Esto no quiere decir que solo van a ejecutar los procesos con prioridad alta. Lo que
generalmente pasa es que el tiempo que un proceso está en estado bloqueado suele ser mayor
al de listo, por lo que en algún momento, los de baja prioridad van a ejecutarse.
El tiempo en unidades que va a ejecutar cada proceso se conoce como ráfaga.
Las E/S no pueden solaparse, se deben hacer una detrás de la otra, y siempre es FIFO.
Los alogritmos se dividen en dos categorías: sin desalojo (sin expulsión), y con dejsalojo (con
expulsión). Los algoritmos sin desalojo, si bien no vemos las interrupciones en los procesos, lo
que podría pasar en dichas intervenciones es que se decida cambiar el proceso sin que este
termine toda su ráfaga. Es en los algoritmos con desalojo en los que sí representamos las
interrupciones.
Los algoritmos con desalojo tienen en cuenta los mismos eventos de los algoritmos sin desalojo
(bloqueo del proceso por syscall y finalización del mismo), y consideran también evento que
derive en un ingreso a la cola de Ready (syscalls de creación de hilos/procesos, o interrupciones
que indiquen fin de ráfaga o fin de I/O). Los algoritmos sin desalojo descartan estos últimos
eventos porque deciden no expropiar la cpu al proceso una vez que la misma fue asignada.
Existen ciertas implicancias de la utilización de planificadores con o sin desalojo en sistemas
operativos de tiempo compartido (o multitarea). El sistema operativo solo puede recuperar el
control de la CPU cuando el proceso finaliza o se bloquea, por lo que un usuario/proceso podría
nunca ejecutar si otro proceso nunca libera el procesador, ya sea por un error o porque
deliberadamente no se bloquea nunca.
Algoritmo FIFO
El primero que llega es el primero en ejecutar. Este es un algoritmo sin desalojo.
Ejemplo:
23
Lucila Canalini
Ejemplo: El proceso 2 llegó mucho antes que la mayoría, pero se postergó por tener una
ráfaga muy larga en comparación al resto. En este caso, el recurso que se le niega es el
procesador.
24
Lucila Canalini
Lo que se ejecuta es lo real, pero lo que se planifica es lo estimado. Es decir, elijo qué
proceso vendrá en base a lo estimado, pero se van a ejecutar los CPUs reales.
Round Robin
Es un algoritmo con desalojo, al que a cada proceso se le dará un quantum (q) de tiempo. Antes
de ejecutar, el Sistema Operativo asignará cuanto tiempo tendrá para ejecutar. Esto quiere decir
que cada q unidades de tiempo, habrá un desalojo. El orden de llegada va a decidir cuál es el
siguiente proceso a ejecutar. Esto es porque se maneja por FIFO.
25
Lucila Canalini
Es muy importante el tamaño de quantum que se define porque de hacerlo mal, podremos
encontrarnos con varios inconvenientes. Un algoritmo con un quantum muy grande termina
siendo igual a un algoritmo de FIFO, y no se aprovecha el desalojo.
El algoritmo más justo es el Round Robin con quantum q=1, porque así todos pueden ejecutar
un poco. Sin embargo, tiene un inconveniente. El Sistema Operativo tiene que hacer
interrupciones en todos los instantes, y esto lleva tiempo, generando más overhead, a diferencia
de si el quantum es más grande.
Por lo tanto, si el quantum es muy grande, el algoritmo degenera en FIFO. Si el quantum es muy
chico, el algoritmo se vuelve más justo porque los procesos avanzan de manera más pareja, pero
genera mucho Overhead por todas las intervenciones necesarias del sistema operativo.
Además, los procesos que tienen ráfagas de CPU muy chicas, sufren un poco más,
principalmente porque nunca terminan de aprovechar todo el quantum.
Prioridades para desempatar (porque si no es FIFO):
1. El que fue interrumpido por el quantum.
2. El que su E/S fue terminada.
3. El que es nuevo (llegada).
Ejemplo: Se define un quantum q=3
26
Lucila Canalini
27
Lucila Canalini
A partir de esto, podemos ver que mientras más tiempo espere el proceso en la cola de listos,
mayor será el valor de R, por lo que mayor será su prioridad. Prioriza a los procesos más cortos
y a los que esperan mucho tiempo en la cola de listos.
El uso de estimadores produce mucho overhead para el Sistema Operativo, y por eso se hace
sin desalojo, para no sumar aún más overhead.
Al ser sin desalojo, el primer proceso que llegue a la cola de listos se ejecutará con su ráfaga
completa. Lo mismo con el resto de los procesos, una vez que se encuentra el proceso que tiene
mayor prioridad y dicho proceso se ejecuta.
Si el cálculo de R es igual, entonces tendrá prioridad el que llegó antes a la cola de listos. Si
llegaron al mismo tiempo, tendrá prioridad el bloqueado, en lugar de él que llegue de proceso
nuevo.
Si hay un único proceso esperando, va ese, no se calcula la R.
Ejemplo: Una vez que se ejecutó el proceso 1, hay que ver qué proceso va a seguir ejecutando.
En el instante 3, el proceso 2 estuvo esperando 2 tiempos en la cola de listos porque llegó en el
instante 1, y tiene 4 unidades de tiempo de ráfaga, por lo que R = (2+4)/4. Por el otro lado, el
proceso 3 estuvo una única unidad de tiempo esperando porque entró en el instante 2, y tiene
para ejecutar una ráfaga e 3 unidades de tiempo, por lo que R = (1+3)/3. La prioridad la tendrá
el proceso 2 porque R2>R1.
28
Lucila Canalini
29
Lucila Canalini
Ejemplo: En este caso en particular, vemos que un proceso que sale de la cola de mayor
prioridad y usa todo su quantum, pasa a una cola de menor prioridad, para que el resto de los
procesos puedan ejecutarse también.
Por lo tanto, habrá cambio de modo siempre que ejecute el Sistema Operativo, y esto será
siempre que haya: una syscall de i/o, una syscall new, una syscall exit, una interrupción, o un
cambio de proceso.
30
Lucila Canalini
Ejemplo:
El proceso 1 tiene dos hilos a nivel usuario. El Sistema Operativo lo ve como uno solo, como si
el proceso 1 fuera un KLT, como lo es el proceso 2.
Como son hilos a nivel usuario, cuando se bloquee uno (ULT1), se bloqueará el otro (ULT2). Es
por eso que cuando entra a E/S el U1, el U2 no puede ejecutar.
Arquitectura de Kernel
El Sistema Operativo es un sistema grande y complejo. Es apropiado dividirlo en componentes
más pequeños. El Kernel es el componente básico que tienen los SO.
31
Lucila Canalini
Tipos de arquitectura:
La primera que apareció fue la MONOLÍTICA. Se la denomina así porque
tiene un solo código, y este se ejecuta en modo kernel, formando todas las
funcionalidades parte de un mismo programa. Si bien está dividido en
módulos (uno para planificación, otro para E/S, etc.), desde cualquier
modulo se puede acceder a cualquier estructura que puede haber en otro
modulo. Así, sus módulos están fuertemente acoplados porque todo
corresponde a un gran programa. Tengo todo disponible en el lugar
correcto, y si quiero algo no necesito mandar un mensaje. Se vuelve muy
difícil de mantener porque si hago un cambio en un módulo, puede afectar
a otro.
La velocidad de acceder de un módulo a otro y obtener información de un momento a otro es
lo que hace que Windows y Linux lo sigan eligiendo, por más que no sea tan robusto.
Con la intención de acomodar dicho kernel monolítico, se creó la
arquitectura en CAPAS. A medida que se va subiendo en capas, se va
pasando por los diferentes módulos que tiene el sistema operativo. Las
capas más bajas serían las más relacionadas con el hardware y las que se
encuentran más arriba son las relacionadas con los usuarios y los
procesos.
También ejecuta en modo kernel, pero la relación entre los módulos no
es como el de la arquitectura monolítica, porque para que los módulos se
puedan comunicar, deben hacerlo a través de sus capas intermedias. Esto
es porque un módulo solo se puede comunicar con módulos adyacentes. Así, la mejora sería que
existen interfaces bien definidas en cada capa, y mientras se hagan cambios en los módulos y
se respeten interfaces, se respetaran los protocolos de comunicación entre las capas y no habría
problemas a la hora de solicitar recursos o hacer consultas a otros módulos del Sistema
Operativo. Sigue siendo un sistema muy grande ejecutando en modo kernel.
Sin embargo, un estudio reveló que cada mil líneas de código,
cincuenta tenían errores. Surgió entonces la arquitectura
MICROKERNEL. Así, decidieron reducir el kernel al máximo. Las
cosas más importantes (esenciales) ejecutarían en modo kernel y
las no tan importantes en modo usuario. En caso de que se
necesitara información, se manda un mensaje a cierto modulo para
que devuelva el valor necesario.
Entre sus ventajas en comparación a las otras arquitecturas, son
fáciles para agregarles funcionalidad. Además, es más robusto y confiable que un kernel
monolítico. Como parte de la funcionalidad del Sistema Operativo que se ejecuta en modo
usuario, es menos probable que ocurran errores graves.
Entre sus desventajas, el paso de mensajes genera un gran volumen de mensajería porque se
comunican con el MicroKernel para hacerlo, y se genera un gran armado de paquetes.
32
Lucila Canalini
Hoy en día se menciona que se usa el monolítico por un lado y el MicroKernel por el otro. Tanto
Windows como Linux se basan en la arquitectura monolítica. Por el otro lado, el sistema
operativo de Mac utiliza la arquitectura MicroKernel, porque tomaron un diseño anterior.
El lenguaje más usado para hacer sistemas operativos es C.
08/05/2020
Concurrencia
Multiprogramación: Cantidad de procesos que se admiten para poder ejecutar. Es un
parámetro que define el sistema.
Multiprocesamiento: Tener varios CPU corriendo, con lo cual me permite correr varios
procesos que están en memoria. Sirve para tener varios hilos corriendo. El multiprocesamiento
implica un sistema que posee varios procesadores. Teniendo en cuenta que sólo puede
ejecutarse un proceso por procesador, entonces existe multiprogramación.
Compartir recursos: Voy a tener datos o información input que requieran ser compartidas
entre procesos o hilos para poder tener un resultado final. El sistema operativo administra los
recursos, asignándolos a cada proceso. Pero es responsabilidad del programador resolver las
cuestiones de concurrencia en secciones críticas y del ordenamiento en la ejecución de los
procesos, para evitar condiciones de carrera.
Competir por recursos: Ver quien llega primero y toma el recurso compartido. Si no me
prevengo que haya dicha competencia y la forma en que lo toma, y que de alguna manera no
genere incoherencias, mi programa devolverá cualquier cosa.
Condición de carrera: Es una condición para ver quien llega primero a la meta. Quien tomara
un recurso primero. Estas condiciones de carrera se producen en secciones críticas.
Sección crítica: Aquel espacio en el código en el cual se hace uso de un recurso visible por los
diferentes procesos y que, en caso de ser escrito o manipulado, cambiando su valor interno de
alguna forma, será una sección critica. Esto es porque si no tenemos en cuenta un mecanismo
que intenta modificarlo, si no lo impedimos podremos tener incoherencias. Más aún si es
modificado de manera concurrente.
Comunicación entre procesos: Que haya datos de un proceso a otro para que puedan
seguir trabajando.
Competencia de los procesos por recursos.
Cooperación de los procesos vía compartición: Podemos tener que los procesos se
comuniquen compartiendo recursos (archivos, pagina en memoria, buffer, etc.). Estos
son espacios que tienen en común los procesos, y van poniendo valores, y pueden ir
pisando los datos. El trabajo concurrente entre los mismos no debería traer
incoherencias. Por ejemplo: Variable global. En la compartición, un proceso puede no
conocer al otro, a diferencia de la comunicación.
33
Lucila Canalini
Sección crítica
Es un pedazo de código con ciertas instrucciones. Para que no haya
incoherencias, hay requisitos que deben cumplirse: exclusión mutua,
progreso, espera limitada y velocidad relativa.
Posibles soluciones
De Software.
Todas las soluciones de software presentan el problema de la espera activa, haciendo un uso
intenso del procesador. Es por esto que la performance es un factor clave que les juega en
contra.
La espera activa (while(turno!=0)) hace que los valores del procesador se vayan a la mierda (no
encontré otra palabra para decirlo).
Soluciones que cumplen con los requisitos de la sección crítica: Algoritmo de Dekker y
Algoritmo de Peterson. Nos permiten generar secciones críticas bien resguardadas. Son
soluciones que garantizan la mutua exclusión.
34
Lucila Canalini
35
Lucila Canalini
36
Lucila Canalini
Los semáforos son recursos del sistema y son limitados. Debe declararse uno por cada recurso
compartido (variable global, impresora, scanner, etc.). Hay que inicializarlo siempre para poder
hacer uso del wait y el signal. Se inicializa según la cantidad de instancias que se tienen de dicho
recurso, a menos que sea una variable global, que en dicho caso se la inicializa en 1.
Dependiendo de lo que se desee hacer, también puede inicializarse en 0, pero nunca en número
negativo. Dicho valor del contador implicaría que está en la cola de bloqueados si está en
negativo. Por eso el valor del semáforo va a ir cambiando a medida que haya nuevos procesos
ejecutando o bloqueados.
Hay semáforos de tipo fuerte, porque hablando de su cola de procesos bloqueados, las trabaja
con una planificación de tipo FIFO. Hay semáforos débiles, que básicamente tienen una
planificación diferente en la cola. Entonces se sacará los procesos de la cola por un criterio
distinto a FIFO.
Existen algunos tipos de semáforos que, en lugar de tener una cola de bloqueados, utilizan
espera activa. Esto tiene sentido en sistemas con multiprocesadores. Los mismos garantizan la
mutua exclusión a través de alguna solución de software (algoritmo de peterson, por ejemplo)
o usando la instrucción de hardware (como test_and_set). Tienen la ventaja de sirven para
sistemas multiprocesador sin generar overhead extra (como sí lo haría el deshabilitar las
interrupciones). Tienen la desventaja de generar una pequeña carga de espera activa.
Existen distintos tipos de semáforos. Hay generales o de contador, y después hay binarios.
Los generales o de contador (N instancias) son los que pueden tener un valor mayor a uno y
puede ser casi infinito. N dependerá de la cantidad de dicho recurso que se tiene disponible.
Los binarios, que son aquellos en los que ponemos valores entre 0 y 1 para representar un
recurso o para intentar representar esa sección critica en la que vamos a utilizar semáforos.
37
Lucila Canalini
Ejemplo: Sistema con tres procesos sincronizados mediante semáforos sabiendo que hay 3
impresoras, 2 scanners y una variable compartida.
Así, declaro un semáforo para el uso de la impresora (inicializado en 3), un semáforo para el
uso del scanner (inicializado en 2), y un semáforo para la variable global (inicializado en 1, pero
no porque haya una sola, sino porque cada variable global se inicializa siempre en 1).
Exclusión mutua
38
Lucila Canalini
Ejemplo: Como existen dos variables compartidas, declaro dos semáforos distintos (uno para
cada una), y ambos se inicializan en 0. Si inicializara un único semáforo, se bloquearía un
proceso usando una de las variables cuando en realidad si puede usarla porque el otro no la
está usando.
Sincronizar
39
Lucila Canalini
Deadlock
Bloqueo permanente de un conjunto procesos donde cada uno de estos procesos está
esperando un evento que sólo puede generar un proceso del conjunto.
Esto quiere decir que, habrá un conjunto de procesos bloqueados indefinidamente. Un proceso
espera que otro haga un signal, este último está esperando que otro haga un signal, y así. Todos
los procesos están esperando a otro a que haga un signal y no va a pasar porque están todos
bloqueados.
El Deadlock (o en español Interbloqueo) es un problema que se presenta en algunas ocasiones
cuando existe una mala sincronización o cuando no hay sincronización. Que ocurra o no puede
depender del orden en que se selecciona un proceso para que utilice el procesador.
Una vez ocurrido el Deadlock entre algunos procesos, esos permanecerán bloqueados
indefinidamente. El resto de los procesos, que no participan del Deadlock y que no comparten
recursos con los procesos involucrados en él, no se ven afectados.
El motivo del bloque indefinido es que un proceso de ese grupo, esta solicita un recurso que se
encuentra asignado a otro proceso del grupo. A su vez, el segundo proceso mencionada solicita
un recurso que fue asignado al primero.
40
Lucila Canalini
Tipos de recursos
Reutilizables: El proceso solicita el recurso, lo usa, lo libera, y después otro proceso
puede volver a usarlo. Se puede modificar, pero seguirá disponible.
Ejemplo: Un archivo (a menos que se lo borre), una variable global, un semáforo, etc.
Consumibles: Recursos que los puedo usar una única vez porque una vez que se usa se
consume y se deshace. No son tan comunes como los reutilizables.
Ejemplo: Una interrupción, un mensaje en un socket. Una vez que se envía y se recibe,
ese mensaje se lo queda a menos que lo reenvíe. No estar más en el buffer para ser leído.
El recurso con tres instancias son tres recursos que no son diferenciables entre sí, sino que los
voy a usar para la misma tarea. Si tengo tres impresoras, y me da lo mismo en cual imprimir,
son el mismo recurso.
Si yo tengo una arista entre el proceso 1 hacia el recurso, significa que estoy solicitando cierta
cantidad de un recurso. Según la cantidad de flechas, es la cantidad de instancias de dicho
recurso que solicito.
Si la flecha va desde el recurso hacia el proceso, quiere decir que dicho recurso ya está asignado
al proceso.
Ejemplo 1: Foto actual del estado del sistema. Va cambiando constantemente.
41
Lucila Canalini
Ciclos
El sentido de las flechas es muy importante para determinar si hay un ciclo o no.
a) Si no hay ciclos, podemos asegurar que en ese instante no hay Deadlock.
b) Si hay un ciclo en el grafo, puede implicar la existencia de Deadlock.
c) Si hay un ciclo y además todos los recursos son de una sola instancia, entonces hay
Deadlock. Única manera de asegurarlo.
Condiciones necesarias:
Si no hay mutua exclusión, los procesos no se bloquearían. Ingresarían todos a la sección
critica, pero habría condición de carrera.
La retención y espera de recursos. Un proceso que ya tenga un recurso asignado y este
solicitando otro. Consiste en que los procesos tienen la facultad de solicitar un recurso, luego el
sistema operativo se lo asigna y mientras lo tiene asignado tiene la posibilidad de solicitar otro.
Si un proceso tiene la facultad de desalojar un recurso del otro proceso, entonces no habrá
problemas para tomarlo. Si el sistema no tiene la política de sacar un recurso a la fuerza de un
proceso, entonces será sin desalojo de recursos. Solo se deja de usar el recurso cuando el
proceso lo libera.
Suficiente:
Espera circular. Es consecuencia de las tres condiciones necesarias.
Cada proceso del mismo (ciclo) está esperando que otro proceso del
mismo grupo libere un recurso.
1. Prevención de Deadlock
Ataca un poco las condiciones mencionadas. Como es necesario que se cumplan las cuatro,
haciendo que una no se cumpla, evitaremos que ocurra Deadlock. Los inconvenientes que tiene
esta técnica son las restricciones que tienen los procesos al momento de pedir recursos.
Los programas no son quienes restringen la manera que tienen los procesos de asignar
recursos, sino que este es el Sistema Operativo.
Para evitar que haya mutua exclusión es generar condiciones de carrera, pero hará que haya
resultados incoherentes. Hay casos en los que estamos seguros que se puedan compartir los
recursos, como cuando son solo de lectura, entonces ahí no se necesita que los recursos tengan
mutua exclusión. Pero si dicha variable es modificable, se vuelve difícil evitarla.
42
Lucila Canalini
Para evitar que haya retención y espera, hay solo dos maneras. Los procesos están muy
afectados a la hora de solicitar recursos. Una es que el Sistema Operativo obligue a los procesos
a que soliciten todos los recursos juntos. La otra es pedirlos de a uno, usarlos y liberarlos,
constantemente. O pedirlos de a grupo. Solicitándolos de a uno o varios, siempre y cuando se
asegure que los va a utilizar y liberar.
Existen dos formas de hacer que haya desalojo de recursos. Una es si un proceso tiene
recursos asignados, solicita uno que no está disponible, entonces debe liberar el resto de los
recursos que sí tiene. La otra es si un proceso A solicita un recurso que está asignado a otro
proceso B que está a la espera de más de recursos, entonces el recurso asignado al proceso B
puede asignarse al proceso A.
El problema es que cuando me bloqueo para buscar el recurso y me lo sacan, me voy a
desbloquear, pero no voy a tener dicho recurso, por lo que me bloquearé de nuevo. Esto puede
causar inanición. Este tipo de estrategias se suele utilizar con recursos que pueden volver al
estado anterior, como lo es por ejemplo una variable, pero con un archivo no sería tan fácil.
Para evitar que haya espera circular se puede asignar un numero de
orden a los recursos. Estos solo pueden solicitarse en orden creciente.
Dicho orden no podrá alterarse.
Un ejemplo de uso podría ser una computadora de un avión, donde las consecuencias de la
ocurrencia del deadlock podrían ser fatales.
Cuando las tareas son muy relevantes, hay que asegurarnos que no haya deadlock. Esto lo
podemos hacer con la estrategia de prevención o con la estrategia de detección de deadlock. Si
existe alto overhead en el sistema en el momento, lo mejor sería utilizar la estrategia de
prevención, porque la de evasión agrega mucho overhead, y como ya contamos con un alto nivel
de overhead, no sería conveniente agregar más.
43
Lucila Canalini
Ambas estrategias de evasión tienen un enfoque pesimista. En cuanto a la Detección, tiene más
overhead porque con cada solicitud es necesario verificar si hay estado inseguro. El algoritmo
de detección se dispara cada cierto tiempo o evento. La estrategia de evasión tiene un enfoque
pesimista porque "ante la duda" deniega la solicitud.
No tenemos la seguridad de que la solicitud denegada iba a producir un Deadlock. Por eso
decimos que es pesimista.
Denegar el inicio de un proceso:
Las necesidades máximas son datos que el proceso declara al sistema operativo antes de
ingresar o cuando ingresa. Asegura que no usara más recursos que los definidos.
Los recursos asignados irán cambiando a medida que se vayan asignando recursos, a diferencia
de las necesidades máximas que serán inamovibles durante toda la ejecución.
A partir de esta información, se tiene todo lo necesario para definir si hay estado seguro o no.
44
Lucila Canalini
Se restan las necesidades máximas y los recursos asignados para conseguir las necesidades
pendientes.
45
Lucila Canalini
estén en mayor aprovechamiento, lo que no es todo el tiempo. Por ejemplo, en una red social,
hay horas pico. Por lo que está bueno que haya un algoritmo que este todo el tiempo revisando
si se produjo deadlock o si se va a producir.
Opciones de Recuperación:
En el proceso 4 ya se sabe que no habrá Deadlock porque no tiene recursos asignados. Por lo
que se lo descartará del análisis desde un principio.
Si no puedo finalizar, entonces todos los que quedaron de esta forma se dirá que están en
Deadlock. Y el recurso que marcamos al principio tampoco podría finalizar, pero no está en
Deadlock, está en inanición por culpa del Deadlock del proceso 1 y el proceso 3.
La recuperación no necesariamente debe ser hecha por el Sistema Operativo. La puedo hacer
yo.
46
Lucila Canalini
Un ejemplo de uso de esta estrategia podría ser una base de datos transaccional, donde los
deadlocks deberían resolverse, pero es más importante la performance del sistema.
4. No hacer nada
La estrategia integrada es la de agrupación de recursos y a cada grupo se le aplica alguna de las
técnicas. Hay que evaluar si prefiero overhead y que no haya Deadlock, o al revés.
Si las tareas que se llevan a cabo, siendo estas las que generan deadlock, no son muy relevantes,
entonces no hacer nada, es decir. No tratar el deadlock, sería la mejor estrategia contra la
posible ocurrencia de tal.
Livelock
Es cuando los procesos avanzan y retroceden constantemente. Es decir, resuelven su Deadlock
y vuelven a dicho estado bloqueado, y así constantemente. También puede ser un problema
permanente. Sus procesos están constantemente intentando avanzar y volviendo para atrás. Un
proceso quiere usar un recurso, pero decide no hacerlo para que lo use otro. Todos los procesos
están haciendo esto, y usan el procesador en abundantemente, a diferencia del Deadlock.
Un bloqueo Livelock consume procesador. Los procesos están constantemente consultando si
pueden utilizar los recursos que solicitan. En cuanto a que los procesos puedan continuar
ejecutando sus instrucciones, es tan grave como el Deadlock. Pero en cuanto al estado general
del sistema, es peor que el Deadlock.
En el Deadlock los procesos quedan estado bloqueado y no vuelven a usar el procesador. En el
Livelock los procesos utilizan el procesador para consultar constantemente por la solicitud del
recurso, ocasionando que el resto de los procesos no involucrados en el Livelock compitan por
el uso del procesador con los que se encuentran en Livelock.
Si dos procesos A y B no comparten recursos, pero existe un Livelock, entonces sí comparten
un recurso, y este es el procesador.
Si el proceso A se encuentra en una situación en la que no termina de ejecutar, tenemos dos
opciones: puede haber deadlock o livelock. Si hay deadlock, el proceso A se puede bloquear
tranquilamente, dejando ejecutar al conjunto B sin problema ya que no comparten recursos.
Pero si hay livelock, el proceso A no permitiría la correcta ejecución del proceso B por estar
utilizando el CPU.
29/05/2020
Memoria real
La memoria real, o memoria física, es la memoria RAM de la computadora.
Para que un proceso o programa pueda ejecutarse, debe estar guardado en memoria. El PCB es
la parte de la memoria que pertenece al sistema operativo.
El proceso está por completo en la memoria excepto cuando se encuentran suspendidos, y están
de manera contigua.
La memoria es un array muy grande, con muchas divisiones indexadas. Cada una de estas
divisiones forman parte de un byte de la memoria. Cada posición tendrá un índice asociado.
47
Lucila Canalini
La memoria no conoce su contenido, por lo que uno puede cargar cualquier programa en la
memoria, y la memoria no sabrá lo que está cargado. Por eso es que puede cargar virus.
Las operaciones que se pueden hacer sobre la memoria son leer y escribir sobre esta. Son cosas
que suele hacer el procesador, aunque existen otros dispositivos que también pueden hacerlo.
Leer algo del procesador es mucho más rápido que leer algo de la memoria, pero la memoria
sigue siendo un componente muy rápido a comparación de otros.
La memoria tiene varios requisitos a cumplir. Los más importantes son:
Reubicación: Característica que tiene que permitir al SO descargar un proceso de
memoria y volver a cargarlo, en el mismo lugar o en otro, sin ningún problema.
Protección: Caso gráfico de que un proceso no puede acceder al espacio de direcciones
de otro proceso. Este es el espacio que ocupa el proceso en memoria. El único que puede
tener dicho acceso es el sistema operativo. Registro base y límite:
Compartición: Poder permitir que dos procesos diferentes accedan a otra posición de
memoria que es diferente a ellos, pero que los dos pueden acceder. El caso ejemplo seria
cuando hablamos de variables que se comparten entre diferentes procesos y ambos
pueden modificarlos y leerlos indistintamente.
Organización física y lógica: Organización física se refiere a que es un dispositivo de
acceso más rápido que el resto de los dispositivos. Es un dispositivo volátil donde van a
estar todos los programas que estén en uso y que se estén ejecutando. Que sea volátil
quiere decir que cuando apago la computadora, se reinicia la memoria. La organización
lógica administra cómo los procesos se almacenan en memoria y como se organizan sin
que se pisen entre sí.
¿Cómo se asignan los programas a una memoria?
48
Lucila Canalini
49
Lucila Canalini
El hardware colabora mucho con el sistema operativo. Debe haber mucha comunicación entre
ellos, para poder administrar la memoria. El MMU es una colaboración que da el hardware para
que haya mejor rendimiento.
Tipos de direcciones en el gráfico:
Dirección relativa: Es un tipo de dirección lógica particular, pero desde un punto conocido.
Dirección lógica: Referencia a una ubicación de memoria utilizada por los procesos, son
independientes de la ubicación real en memoria. Esta dirección pasa por un proceso de
traducción para conseguir así la dirección física.
Dirección absoluta: Donde realmente se va a ubicar la dirección que estoy buscando.
50
Lucila Canalini
Enlace dinámico
El código debe estar todo en memoria, incluso las bibliotecas compartidas, pero solo cargamos
una parte del programa. Dejamos pequeñas referencias dentro de nuestro programa que hace
que se cargue una biblioteca a medida que la vamos necesitando.
Las bibliotecas del sistema siguen estando en el proceso, por lo que siguen ocupando espacio
en el disco y en memoria, por lo que no es mucho mejor que el caso anterior.
Las bibliotecas que se van enlazando, se van agregando a la imagen del proceso, por lo que toda
la memoria se irá expandiendo.
51
Lucila Canalini
¿Cómo se organiza el sistema operativo para que los procesos no se pisen entre
sí mientras utilizan la memoria?
Un proceso no puede acceder al espacio de direcciones de otro proceso, por default. Pero
existen mecanismos, como lo es la biblioteca compartida, que sí permite que dos procesos
accedan a una misma posición.
Una de las actividades/operaciones principales que tiene el sistema de gestión de la memoria
del sistema operativo tiene que ver con la carga de procesos en memoria, y cómo luego se
organizan para que no se pisen. Tener una buena gestión de memoria es que la
multiprogramación, la convivencia entre otros procesos, sea lo más eficiente posible.
Fragmentación
Fragmentación externa: Este tipo de fragmentación se genera por la aparición de huecos a
medida que voy asignando los procesos.
Fragmentación interna: Espacio de una partición que no podrá usar otro proceso. Es un
problema que puede aparecer varias veces, o en varios esquemas en los que tengamos algún
tipo de particionamiento fijo. Las particiones dinámicas no sufren fragmentación interna
debido a que se asigna a cada proceso, el espacio que necesita. La compactación es un
procedimiento que se utiliza para generar huecos más grandes en memoria para reducir la
fragmentación externa.
Particionamiento fijo
Es el más simple de todos. Se divide la memoria en particiones de tamaños fijos y contiguo. En
cada uno de estos espacios puedo cargar un solo proceso. El proceso se ubica en alguna
partición del mismo tamaño o menor que el proceso. Un proceso no puede cargarse en más de
una partición, por lo que habrá una relación de uno a uno entre el proceso y la partición.
Este esquema tiene fragmentación interna, pero no tiene problemas de fragmentación
externa.
52
Lucila Canalini
Dos maneras de organizar el particionamiento fijo. Ya no se usan porque ninguno de los dos es
muy eficiente.
Todas las particiones del mismo tamaño: Las limitaciones de este ejemplo es que, si
tengo un proceso que ocupa más lugar que el tamaño fijado, no puedo almacenarlo.
Además, hay otro problema es que no puedo agregar procesos si ya se ocuparon todas
las particiones.
Particiones de tamaños diferentes: Tengo número fijo de particiones, y si tengo un
proceso de 11 megas, solo podre ponerlo en la partición que tenga mínimo este tamaño,
entonces hasta que esta no se libere, no podre guardarlo. Lo mismo pasa si tengo un
proceso que usa espacio que no hay partición que pueda soportarlo.
Para este último, cuando las particiones son de diferentes tamaños, puedo tener colas para ir
asignando los procesos a cada partición. Es efectivo porque aprovecho el espacio de mejor
manera, pero podría pasar que un proceso podría ubicarlo en una partición muy grande.
Esto puede solucionarse si tengo una única cola, por lo que, si entra un proceso chico, podre
cargarlo en cualquier partición libre. Esto permitiría el multiprocesamiento al máximo.
53
Lucila Canalini
Particionamiento dinámico
A cada proceso se le va a asignar la memoria que esté disponible según lo que necesita. No tengo
una cantidad de particiones disponibles, sino que tengo toda la memoria para poder cargar
procesos, siempre y cuando haya espacio. A cada proceso le asigno exactamente lo que va a
usar. A diferencia del particionamiento fijo, este tiene fragmentación externa, pero no interna.
A medida que los procesos se cargan y se descargan en la memoria, se irán formando diferentes
huecos. Ahora tendré un inicio y un tamaño, sobre la información de la ocupación de memoria
de cada proceso.
No hay fragmentación interna porque lo que va a pasar es que no va a ocupar exactamente todos
los megas del hueco (según el caso) y el resto se convertirá en un nuevo hueco, de los megas
restantes que no ocupo el nuevo proceso.
Para saber el tamaño de un proceso, lo sabe el sistema operativo de entrada.
Con las tablas de procesos y huecos es que puedo hacer el seguimiento de los huecos de
memoria disponibles dentro del sistema operativo.
54
Lucila Canalini
Los últimos dos tienen el problema que después de mucha carga y descarga, tendré muchos
huecos y de pequeños tamaños. Por esta razón mejor ajuste y peor ajuste son los peores
algoritmos.
Problema:
Solución:
Compactación: Aumenta el grado de multiprogramación porque permite que se puedan ubicar
más procesos al sistema. Reubica a todos los procesos en una de las esquinas de la memoria (la
parte más baja o la más alta). Así, genero huecos más grandes para que entren procesos que
antes no podían.
El problema es que no reservo espacio para ningún proceso en memoria que quiera crecer. Otro
problema es que no puedo usar la memoria mientras haga la compactación, por lo que no podré
ejecutar los procesos porque las instrucciones de los procesos se encuentran en memoria.
Entonces, no podré utilizar los procesos hasta que la compactación no termine. Por lo tanto,
habrá mucho overhead.
55
Lucila Canalini
Buddy System
Compensa desventajas de particionamiento fijo y dinámico. Para esto se asigna a los procesos
tamaños de memoria que son potencias de dos (2^n). La memoria asignada es según el tamaño
del proceso y se redondea a la siguiente potencia de dos. Tiene tanto fragmentación interna
como externa.
Buddy System sufre fragmentación interna y externa porque utiliza particiones de tamaño
fijo (potencias de 2) y porque, según como se dividan, podría ser que no queden particiones
contiguas.
Ejemplo: Tengo una memoria de 1024 MB y llega un proceso de tamaño 200 MB. Lo que tendré
que hacer es dividir mi memoria hasta llegar a tener partición de 256 MB al ser la siguiente
potencia de 2 viéndolo desde el tamaño del proceso que quiero ingresar.
La divido en 2 una vez y estará dividida en dos particiones de 512 MB. Lo divido una vez más y
tendré dos de 256 MB (porque no es necesario dividir las dos divisiones de 512 MB). Ahora
asignaré el proceso en una de las particiones de 256 MB.
Si llega uno de 100, deberé ubicarlo en una partición de 128 MB al ser esta la siguiente potencia
de 2, por lo que vuelvo a dividir. Divido la partición que me quedó de 256 MB sin ocupar, y al
tener las dos divisiones de 128, agrego el de 100 en una de ellas.
Tratamos de darle al proceso exactamente lo que necesita. Para que sea exactamente, el tamaño
del proceso debe ser potencia de 2, como lo es el proceso 4, pero no suele pasar que justo sea la
misma. Así, ayuda al problema que traía la compactación. La consolidación es tan solo un
movimiento de punteros.
La consolidación se hará siempre y es cuando se libera un espacio y se une con uno o dos
espacios libres que tiene a sus costados.
Segmentación
Primero de los esquemas donde el proceso no necesita estar contiguo en memoria para poder
cargarse. En los otros tres esquemas mencionados, necesitamos tener un hueco con la
capacidad suficiente para que el proceso pueda entrar de manera completa. En la segmentación,
el proceso se puede dividir en dos y poner una división en un hueco, y otra en otro.
56
Lucila Canalini
El proceso se divide en segmentos de tamaño variable, y cada segmento representa una parte
del proceso desde la visión del programador: código, pila, datos, biblioteca, heap.
La segmentación sufre fragmentación externa pero menos que el Particionamiento Dinámico.
Esto es debido a que al dividir los procesos en fragmentos más pequeños (segmentos), es más
probable encontrar huecos para cada uno de los segmentos del proceso. Cada segmento tendrá,
exactamente el espacio que necesita.
En la tabla de segmentos del proceso, a diferencia de las tablas que teníamos en los otros
esquemas, la cual relacionaba al proceso con el espacio de memoria que iba a utilizar según el
esquema, se tiene el inicio y el fin del segmento. El número de cada segmento de la tabla, se
relaciona con el índice de la tabla.
Muy parecido a lo que pasaba en el particionamiento dinámico, este esquema tiene
fragmentación externa. Es bueno porque se evita hacer proceso de compactación tan seguido.
Para poder calcular la dirección física, debo utilizar esta tabla de segmentos.
57
Lucila Canalini
1 byte = 8 bits
Si tengo un sistema operativo de 32 bits, mis direcciones serán de 32 bits y no cambiarán hasta
que no cambie el sistema operativo.
Paginación
A diferencia de la segmentación, en la paginación se divide al proceso en partes iguales
(páginas), pero al igual que el anterior, no estará contiguo en memoria.
La memoria se divide en marcos, del mismo tamaño que las páginas, por lo que también son
fijos. Este tamaño suele ser chico. Al ser tan chico en comparación al tamaño de la memoria,
siempre se encontrará una disponible. El tamaño de cada página lo define el sistema operativo,
pero no puede elegir cualquier tamaño. El procesador indica el tamaño máximo y mínimo que
puede tener cada página. Ya de por si estos tamaños son potencias de 2.
En la última página puede que haya un pedazo que quede sin usar. Esa será la fragmentación
interna, y solo ocurrirá en la última página de cada proceso. No hay fragmentación externa.
Esto es porque cualquier página puede ir a cualquier marco que este disponible. Si no hay
disponible es otro problema.
Cada proceso tendrá su propia tabla de páginas. La MMU necesitará un acceso para leer la tabla
de páginas y determinar en qué marco de la memoria se encuentra. Luego se hará un segundo
acceso para obtener el dato solicitado. La compartición es simple. Los procesos pueden
compartir marcos de memoria, simplemente ubicando el mismo marco en tablas de páginas
diferentes.
Habrá una relacion entre cada página y el frame que ocupa, para saber en qué espacio de
memoria se encuentra la página que estoy buscando. Esta tabla es una estructura que necesito
hacer.
58
Lucila Canalini
La cantidad de bits asignados al numero de pagina me dira la cantidad maxima de paginas por
proceso. La cantidad de bits asignados al desplazamiento, será exactamente el tamaño de la
pagina.
59
Lucila Canalini
Protección: Al estar dividido en paginas, podria pasar que, teniendo mi codigo y mi pila, quizas
me quda una pagina ocupando un poco de código y un poco de pila, se queda en el medio. Ahí,
la proteccion no es tan eficiente como lo es para la segmentacion.
Compartición: Cuando dos paginas de dos procesos distintos apuntan al mismo frame, estan
compartiendo memoria.
Tabla de marcos libres: Estructura adicional a la tabla de paginas por procesos. No es mas que
cualquier estructura que me permite diferenciar qué marco esta libre y cual esta ocupado. No
necesariamente tiene que ser un mapa de bits como en el ejemplo, por mas que sean los mas
adecuados al ser rapidos de leer.
Ejemplo de Paginacion:
Si cada pagina tiene un tamaño de 512 bytes, entonces las primeras 511 direcciones logicas
seran: 0-0, 0-1, 0-2, …, 0-511. Esto es 0 por el número de página, y el otro número es el
desplazamiento. La siguiente direccion logica sera 1-0, y la siguiente 1-1, 1-2, …, 1-511. Por lo
tanto, la direccion logica 1-258 es en realidad (1x512) + 258.
Ejemplo de un proceso: Direcciones de 4 bits y Máximo tamaño de un proceso de 16 bits.
Dividido en páginas de 4 bytes.
60
Lucila Canalini
Sabemos que la direccion es de 4 bits, y sabemos que las paginas son de 4 bytes, entonces el
tamaño de pagina es 2^2, por lo tanto, 2 bits. Para saber los bits del número de página tengo
que hacer direccion logica = numero de pagina – offset, osea, que si la dirección lógica es de 4
bits y mi tamaño de página es de 2 bits, tendré otros 2 bits para el numero de pagina.
Si la paginación fuese jerárquica de 2 niveles, entonces la direccion logica no seria la misma.
El numero de pagina se dividiria en dos, por lo tanto, será 1 bit para cada uno. Hay que hacer
tres accesos, mientras que antes eran solo dos. Es util para cuando el proceso tiene muchas
paginas.
Segmentación paginada
Los procesos se dividen en segmentos como ocurría en la segmentación, los cuales podían tener
tamaños variables. A su vez, esos segmentos se dividiran en paginas, de tamaño fijo. Combina
las ventajas de la segmentacion y las de la paginacion. Así, me quedo con un poco de
fragmentacion interna pero sin fragmentacion externa. Tiene el problema extra que para
llegar a una posicion de memoria hay que hacer mucha busqueda, teniendo menos rendimiento.
61
Lucila Canalini
Memoria virtual
La memoria virtual el es espacio de memoria secundaria (el disco) que puede ser direccionado
como si fuese memoria real. Hoy en dia, la falta de memoria no es un problema tan caro.
Nos permite agrandar nuestra memoria. Para hacer esto, necesita dos características. Una es la
traducción de direcciones, que si o si se debe calcular en tiempo de ejecucion. La otra es que
el proceso debe estar dividido en partes (paginas o segmentos). Constantemente estaremos
pasando partes de un proceso en disco (es decir, memoria virtual) a memoria principal.
Necesito que cuando los procesos vuelvan a memoria puedan entrar en diferentes lugares de la
memoria, no necesariamente al lugar donde estaban antes.
Motivaciones:
Durante la ejecución del proceso no se usan todas sus partes (páginas o segmentos).
Espacio reservado sin usar. Puedo usarlo para otras cosas.
Ventajas
Un proceso puede ser más grande que la memoria principal. Esto es porque lo puedo
cargar en memoria virtual, y en memoria real solo tengo las paginas que voy
necesitando (si utilizo paginacion).
Más procesos en memoria. Permite aumentar el grado de multiprogramacion.
Menos restricciones para el programador.
62
Lucila Canalini
63
Lucila Canalini
Eficiencia
Requiere más accesos a memoria.
Requiere más accesos a disco.
No mejora el rendimiento para la ejecución del proceso.
No es beneficioso para la ejecución del proceso en sí. Este es el costo que tengo que pagar para
poder tener las ventajas anteriormente mencionadas. La conclusión seria que no es muy
eficiente.
64
Lucila Canalini
Cambiará mi dirección lógica. El puntero a tabla será un índice que apunta a alguna de las
posiciones de la tabla de punteros a tablas de páginas.
Con el número de página busco el desplazamiento dentro de la tabla de páginas, para encontrar
el marco que realmente necesito. Una vez obtenido el marco, puedo convertir la dirección lógica
en dirección física, que al igual que en la paginación, será el número de marco y el
desplazamiento.
65
Lucila Canalini
Si otro proceso requiere también una página 10 pero que nada tiene que ver con la pagina 10
que solicito el proceso anterior, se puede utilizar una función de hash para hacer un acceso a la
tabla y no una búsqueda secuencial, devolviéndonos el marco donde se encuentra dicha página
de dicho proceso. Puede que la función de hash nos devuelva la misma posición que al proceso
anterior, por lo que se generaría una colisión. Para evitar esto, se agrega una nueva columna a
la tabla de páginas invertida, la cual contendrá un puntero.
66
Lucila Canalini
Siempre que se busca un marco se deberá hacer un acceso a la TLB. Si no se encuentra la página
ahí, debo hacer un acceso a la Tabla de Paginas. Al tener la TLB, obtendremos el marco que
buscamos mucho más rápido. Es una memoria cache, pero está dentro del procesador.
No guarda páginas, sino que guarda partes de la tabla de páginas, que es la información que
relaciona a la página y al número de marco para poder encontrarlo.
Si la MMU consulta a la TLB y encuentra lo que busca, se ahorrara el acceso a memoria. Lo cual
es muy beneficioso porque estamos hablando de un acceso a memoria que son nano segundos,
pero hay miles de accesos ocurriendo en un segundo. Así, mejora bastante el rendimiento
general del sistema.
El problema que tiene es que es chica. No entra toda una tabla de páginas, sino que tiene pocas
entradas.
Tanto la MMU y el Sistema Operativo pueden acceder a la TLB. La MMU entra para buscar
páginas, y el SO para actualizarlas y hacer cambios.
67
Lucila Canalini
Política de recuperación
Esta es la política de traer paginas a memoria.
Tenemos dos técnicas al momento de iniciar la carga de un proceso de disco a memoria. Uno es
paginación bajo demanda, que es por default. Este es que cuando se genera un fallo de página,
traigo a memoria la página que necesito.
El otro es la paginación adelantada, que se basa en que cuando ocurre el fallo de página, traigo
la página que necesito y por las dudas traigo unas más. Esto es porque existe la posibilidad de
que las necesite más adelante. El disco se divide en bloques de tamaño fijo, y quizás en uno de
esos entra más de una página. Por lo tanto, cuando me traigo un bloque, me traigo varias
páginas.
Política de ubicación
Hasta el momento vimos que la memoria virtual fueron todos sobre paginación, pero la
memoria virtual también es válida cuando hablamos de segmentación pura, y esta política está
relacionada principalmente con esta.
Aquí, tendremos un segmento de memoria cuyo tamaño desconocemos, y debemos ubicar en
algún hueco de memoria. Para hacerlo, usamos los algoritmos del particionamiento dinámico:
best fit, first fit, next fit, y worst fit.
Esta política únicamente aplica a segmentación porque hay que buscar un hueco que se
ajuste al tamaño del segmento que quiero traer de disco a memoria.
Políticas de reemplazo/sustitución
Una de las más importantes al momento de diseñar el sistema
operativo.
La definición de algoritmos que me permitan elegir el marco
que será la víctima, que pasará de la memoria al disco cuando
quiera traer un marco de disco a memoria, pero no tengo más lugar
para ubicarlo.
Dichos algoritmos son, entre otros: optimo, FIFO, LRU, Clock, Clock
mejorado. El objetivo de estos algoritmos es reducir los fallos de
página.
El mejor de todos estos algoritmos es el óptimo. Lo que hace es seleccionar a la víctima a partir
de la elección a la página a la que se realizara una referencia en el futuro más lejano.
De las páginas que tengo en memoria real, llevaré una a disco para poder traer otra. Eligirá la
que no se va a utilizar en el futuro más cercano. Esto es elegir la que genere menos page fault
mas adelante.
Si bien es el que mejores resultados trae, no puede implementarse. Solo se tiene para
compararse con otros algoritmos. Esto es porque si en una situación determinada me genera
10 fallos de página el algoritmo óptimo, y encuentro otro que genera 11, puedo decir que dicho
algoritmo es bueno, porque genera casi tanto page fault como el algoritmo óptimo.
68
Lucila Canalini
En el algoritmo FIFO elijo como víctima la página que más tiempo lleva en memoria.
Lo único que necesito para implementarlo con respecto a la tabla de páginas es actualizar un
puntero a la página próxima que será reemplazada. No requiere un formato diferente ni mucha
información adicional.
El LRU (Least Recently Used) lo que hace es elegir el menos recientemente usado, es decir, el
que se usó hace más tiempo en comparación al resto de las páginas. Esto es la página que hace
más tiempo no es referenciada.
Su ventaja con respecto al FIFO es que tal vez no se usó todavía el que acaba de entrar. FIFO
sacaría el que primero llegó, por más que todavía no se haya utilizado, mientras que LRU sacaría
el que ya utilizó.
Para este algoritmo, mi tabla de página tiene que ser más compleja. Mínimamente tiene un
numero de marco, un bit de presencia, y el bit de modificado. Pero en LRU deberá tener
además el instante de referencia, para poder compararlos y elegir a la víctima.
Tiene más overhead que el resto de los algoritmos. Esto es porque tenemos una tabla que nos
indica cuándo fue utilizada cada página. Constantemente, y miles de veces por segundo, se
comparan dos números para fijarse cuál es el más grande y para ver cuál dejar.
Luego está el algoritmo de Reloj o de Segunda Oportunidad (Clock). En este algoritmo, el menos
recientemente usado (LRU), lo reduzco a lo máximo que es 1 bit. Por lo tanto, en la tabla de
páginas de un proceso, cada vez que cargue o use una página (leerla o escribirla), el bit de uso
se pondrá en 1.
Tengo un puntero y pregunto si el Bit de uso está en 0 o en 1. Así sucesivamente hasta que el
Bit de uso esté en 0. Ese será el elegido como víctima para sacar la página de memoria y llevarla
a disco.
Si (Bit de uso == 0) Se reemplaza el marco.
Si (Bit de uso == 1) Bit de Uso = 0 y se apunta al siguiente marco, volviendo a
preguntar.
Si se analizan todos y ninguno está en 0, se vuelve a empezar, por lo que, si o si encontraré uno
en 0 porque si eran 1 en la primera vuelta, los cambié a 0 antes de pasar al siguiente marco.
Su tabla de páginas tendrá una columna nueva que será el bit de uso. Dicha columna no genera
mucho overhead.
69
Lucila Canalini
Ejemplo:
Retoma el algoritmo a partir de donde se quedó la aguja del reloj. Es decir, cada vez que hay
page fault, se fijará en donde está apuntando el puntero para evaluar cuál será la víctima. Si
antes de que haya un page fault, la pagina 45 en el marco 2 se utilizó, su Bit de uso cambiará a
1, por lo que se le dará una segunda oportunidad porque se lo habría utilizado como víctima si
antes de su utilización hubiese habido un page fault.
Por cada page fault me llevo una única página a disco para hacer lugar para esta nueva página.
El algoritmo de Clock Mejorado, además de tener el Bit de uso, tendrá una columna extra que
es el Bit de modificado.
(u=0; m=0): No accedido recientemente, no modificado.
(u=1; m=0): Accedido recientemente, no modificado.
(u=0; m=1): No accedido recientemente, modificado.
(u=1; m=1): Accedido recientemente, modificado.
Estas distinciones son para que, cuando elijo una víctima que fue modificada, tengo el acceso
adicional a disco para actualizar. Entonces, tal vez me conviene elegir una que no fue
recientemente usada, y que además no haya sido modificada.
Cuando se produzca un page fault, voy a recorrer todo el reloj hasta encontrar uno que cumpla
(u=0;m=0), para seleccionarlo como víctima. Si no lo encuentra, recorre los marcos y selecciona
el primero que cumpla con (u=0;m=1). A medida que recorre, al igual que el algoritmo de Clock,
modifica el bit de uso de cada marca de 1 a 0, pero eso lo hace en la segunda vuelta, es decir,
cuando empieza a verificar si hay alguno que cumpla que (u=0;m=1). A medida que ve que no
cumple, le apaga el bit de uso. Pero cuando hace la primera vuelta verificando si alguno cumple
(u=0;m=u), no modifica nada.
Puede que tampoco encuentre a nadie durante la segunda vuelta, por lo tanto, vuelve a repetir
el primer paso, y de ser necesario, el segundo paso también. Esto asegura que se encuentre una
víctima. Cuando elijo la víctima, la saco de memoria, pongo en el mismo lugar la página que
traigo de disco, y paso mi puntero a que apunte a la siguiente posición, cosa de que cuando haya
otro page fault, empiece a evaluar desde ahí.
El overhead en comparación al algoritmo de Clock, dependerá. En el peor de los casos
tendremos que dar 4 vueltas, mientras que en el Clock en el peor de los casos tendremos que
dar 2 vueltas. Parecería que genera más overhead pero al mismo tiempo, este algoritmo analiza
si hay que hacer escrituras en disco. Entonces, tiene más overhead a la hora de usar el algoritmo,
pero me ahorro acceso a disco.
70
Lucila Canalini
Ejemplo:
Tanto para este algoritmo como para el de Clock, el puntero comienza a moverse cuando haya
page fault.
La asignación fija y reemplazo global no es posible porque si le saco una página o un marco a
otro proceso y me lo asigno, paso a tener un marco más asignado, por lo que deja de ser fija.
71
Lucila Canalini
Política de limpieza
Limpieza bajo demanda.
Limpieza adelantada.
Consideraciones
Sobrepaginación/Trashing (Trasiego)
Una de las ventajas de la memoria es aumentar el grado de multiprogramación. Si tenemos
muchos procesos en memoria y por cada proceso hay pocos marcos, a medida que el proceso
vaya ejecutando, existe la posibilidad de que se produzcan más fallos de página. Esto significa
que voy a estar mucho tiempo trasladando o moviendo páginas de disco a memoria.
Si no tengo algún tipo de métrica con recomendaciones, podemos pensar que si usamos poco la
CPU es porque tenemos pocos procesos en memoria. Si es baja mi tasa de uso de CPU, puedo
aumentar el grado de multiprogramación. Pero si agrego más procesos a memoria, tendré más
fallos de página, porque la cantidad de marcos no aumenta. Llegaré a una situación en la que
tendré más fallos de páginas que lo que avanzo en la ejecución de procesos.
Este traslado de páginas de memoria a disco se lo conoce como sobrepaginacion. Donde
simplemente el problema es que hay muchos fallos de página, significando que hay mucha
entrada y salida, es decir, alta utilización del disco y bajo uso de la CPU. Se invierte más
tiempo en el mecanismo de paginación que en la ejecución del proceso.
Solución: Para solucionar esto se pueden hacer dos cosas. Una es en la que se usan muchos
recursos, y la solución es comprar más memoria. La que usa menos recursos es ir liberando
procesos, lo que no es muy recomendable, por lo que la opción anterior sería la mejor.
No es una solución agregar un procesador. Esto es porque no solo sería más caro, sino que,
además, la curva sería parecida pero el trashing ocurriría más rápido. Tener más procesador
hace que el problema llegue más rápido nada más.
Tamaño de las páginas
Si bien el hardware nos ofrece el tamaño de páginas que podemos usar, es el Sistema Operativo
quien elige el tamaño. El tamaño estándar suele ser páginas de 4 KB, pero pueden ser de menos
o de más.
Estas son características que se dan dependiendo de si el tamaño de página es grande o chico:
72
Lucila Canalini
Si elegimos tablas de páginas que tengan pocas entradas porque las paginas son grandes, nos
pueden generar algunos problemas que no ocurrirían si tenemos tablas grandes con paginas
chicas. Este tipo de desventajas vienen de la mano de los fallos de páginas. Si tenemos paginas
chicas (muchas páginas para el proceso) hay más chances de tener fallos de páginas. El mismo
razonamiento se utiliza para los fallos de TLB.
En la paginación solo tenemos fragmentación interna en la última página del proceso. Si las
paginas son más grandes, hay chandes de que la fragmentación sea más grande.
Con respecto a la localidad es más preciso porque tengo menos espacio en memoria.
La transferencia de E/S de la tabla es con un fallo de página.
Bloqueo de páginas
Se tiene un proceso A de alta prioridad y uno B de baja prioridad, y está ejecutando el B.
Mientras ejecuta genera un fallo de página por lo que es bloqueado, y pasa a ejecutar el A. Puede
pasar que en algún momento se atienda el fallo de página del proceso B y este pase a estar listo
para ejecutar. Pero también puede pasar que el A genere un fallo de página, y cuando se atiende,
podría ser que, cuando todos vuelven a memoria, el proceso B pueda sufrir inanición por ser un
proceso de baja prioridad.
La página que se trajo para el proceso B va a ser una página que no se usa hace mucho tiempo
y que además no fue modificada. Por lo tanto, esa página será elegida como víctima
seguramente. Se da esta situación por la inanición del proceso B. Para estos casos se puede
bloquear la página hasta que el proceso B pueda usarlo, porque si ya la tiene en memoria, y es
elegida como víctima, cuando vuelva va a pasar lo mismo.
Esto es lo que pasa:
1. PB provoca un fallo de página.
2. PB es bloqueado hasta tener la página solicitada.
3. PA es asignado al CPU.
4. PA provoca un fallo de página.
5. La página solicitada por PB se carga en memoria y PB se desbloquea.
6. PB puede sufrir inanición y la página que solicitó no fue modificada y permanece mucho
tiempo en memoria.
7. La página solicitada por PA sustituye a la de PB.
73
Lucila Canalini
Así se soluciona:
Estructura de programas
A nivel hardware, las matrices no son más que memoria. Entonces, habrá una diferencia si lo
recorremos por fila o por columnas.
Por cada fila hay una página. Por lo tanto, si tenemos memoria virtual, si leo por fila, cargo la
primera página y leo por completo. Cargo la segunda página y leo por completo. Y así.
Pero el problema estará si leo por columna. Lo que pasara es que habrá un page fault por cada
lectura.
74
Lucila Canalini
De todas maneras, este problema ya no existe porque el mismo compilador hace modificaciones
para que el recorrido tenga que hacerse por filas. Por lo tanto, el problema se resuelve en la
etapa de compilación.
Para los instantes 1, 2 y 4 tengo page fault porque necesito dos páginas que no tengo en la
memoria principal. En el instante 3 no porque solicito el uso de la página 2 pero ya la tengo en
memoria. En el instante 5 tengo page fault y decidó sacar a la página 1 para poner la página 5
porque si miro el futuro, no necesitaré esa página, al menos en esta traza.
Los primeros tres PF son obligatorios, por eso cuando se hace la suma total para la conclusión
la divido en 3PF + 3PF = 6PF.
El principio será igual al caso anterior. En el instante 5 reemplazo la página 2 por la 5 porque
esa fue la primera que entró (FIFO).
Vemos el problema en el instante 6, porque en el instante anterior justo reemplazó la que se
estaba por usar en el instante siguiente.
Lo normal sería que ningún algoritmo genere menos fallos de página que el algoritmo óptimo.
75
Lucila Canalini
Los primeros cuatro pasos son iguales. En el instante 5 se fija cual fue la que usó hace más
tiempo de las tres que tiene en memoria. La 3 la usó en el instante dos, la 2 la usó en el instante
tres, y la 1 la usó en el instante 4, por lo que la que hace más tiempo que no usa es la 3, así que
la reemplaza por esa.
El asterisco indica que el bit de uso está en 1. En el instante 5 hay page fault y evalúa todas las
páginas que tiene en memoria. Las tres tienen el bit de uso en 1, entonces evalúa uno a uno, y
pasa su bit de uso a 0. Cuando termina de evaluar la tercera página, vuelve a evaluar porque no
encontró ninguna en cero. Cuando vuelve a empezar, ve que la primera está en 0, por lo que
será la víctima, y el puntero pasará a apuntar a la siguiente página.
Las páginas siempre entran con el bit de uso igualado a 1. Y cuando se vuelve a usar una página
que ya está en memoria, pero su bit de uso está en 0, la uso y le aumento el bit de uso a 1.
Conclusión: El mejor de todos será el algoritmo óptimo, que no se puede implementar. Luego,
LRU será el segundo mejor, el Clock el siguiente, y el FIFO será el peor.
LRU es más preciso que el algoritmo de Clock porque usa para la selección de la víctima,
exactamente el último momento en que se usó. En cambio, el clock, apenas, aproxima si se
utilizó o no recientemente usando un bit de uso. Con respecto a la eficiencia desde el punto de
vista del overhead, el algoritmo Clock genera menos overhead que LRU. Pero desde el punto de
vista de los fallos de página, LRU es más eficiente que Clock.
12/06/2020
File System
Es una abstracción que tiene el Sistema Operativo para poder almacenar todo lo que
tenemos en memoria, persistirlo, por el hecho de que, si apagamos la máquina, todo lo que
tenemos en memoria se pierde, y no es la idea tener que regenerarlo cada vez que la volvemos
a encender.
Le permite gestionar el almacenamiento de datos y programas tanto al Sistema Operativo como
a los usuarios. A estos últimos les permite que, si están trabajando en un documento, a través
de un programa, lo que fuese, todo lo que va procesando, se va almacenando para tomarlo en
un siguiente punto y seguir ejecutando. Básicamente, permite que no se pierdan los datos.
76
Lucila Canalini
Objetivos:
Soporte para varios usuarios. Implica protección. Si dos personas están trabajando y
tienen archivos que no quieren que el otro vea, entonces el File System provee un
mecanismo mediante el cual se asegura de que esto se cumpla. Permite a ciertos
usuarios que tienen permiso operar, y a otros se les restringe.
Maximizar el desempeño del sistema. Que sea lo más rápido y ágil posible.
o SO: Administrar espacio en disco y aprovecharlo. Cuando el Sistema
Operativo nos gestione el file system, el almacenamiento se haga de la mejor
manera para que los megas que se tiene disponibles no los desperdicie por tener
una mala administración.
o Usuario: Tiempo de respuesta. Si guardo un archivo o lo leo, que se pueda
hacer lo más rápido posible.
Soporte para distintos tipos de dispositivos. Uno no tiene que andar haciendo
operativas. Solo se necesita que el Sistema Operativo lo monte y lo disponga para que
uno lo pueda usar. Nos crea una interfaz estandarizada para los procesos de los
usuarios. Y a los dispositivos los abstrae, permitiéndonos operar con el File System de
manera independiente, sin importar el dispositivo del otro lado.
Archivos
La estructura más básica para poder almacenar cualquier dato en el File System, es un archivo.
Todo lo que queramos almacenar mediante el File System, ya sea en un disco rígido, en un
pendrive, lo haremos a través de un archivo. Los archivos son un conjunto de datos
relacionados y se persiste en el tiempo dentro de un dispositivo de almacenamiento. Esto
quiere decir que sin importar cuanto tiempo pase sin abrirlo, se mantendrá igual.
Los archivos tienen ciertos atributos: nombre, identificador, tipo, ubicación, tamaño, permisos,
fechas, propietario.
El nombre en general es para el usuario, mientras que el Sistema Operativo puede operar a
través del identificador numérico. El tamaño es coherente con la cantidad de datos
almacenados dentro de él.
Los permisos se basan en quienes pueden leerlos, escribirlos, o ejecutarlos (en el caso de
Linux).
77
Lucila Canalini
La fecha es para tener una traza de la actualización y del uso del archivo.
El propietario es quien lo crea y lo tiene en su poder. Este brinda los permisos para el acceso
al archivo.
La ubicación en si es algo que, aunque no se ve, uno sabe que está dentro de un directorio, y
dentro de esta ubicación se encuentran los datos.
Los archivos no tienen un único formato. Según el formato tendremos diferentes tipos de
archivos. Algunos son únicos para el Sistema Operativo, que el usuario no conoce. Otros son
propios de uso del usuario.
Todas las operaciones que queramos persistir, vamos a guardarla en dichos archivos, y los
mismos vamos a operarlos. Las operaciones se representan a través de llamadas al sistema.
Operaciones básicas: Crear, abrir, leer, renombrar (mover), truncar, borrar, cerrar,
escribir, reposicionar.
Crear es definir un nuevo archivo y posicionarlo dentro de la estructura del File System.
Para abrir el archivo este debe estar creado. Abrirlo es traer ciertas estructuras del archivo a
memoria para poder operar con él.
Cerrarlo es cuando ya no necesito usarlo, y se lo saca de dicha posición dentro del File System.
Cuando uno lo cierra, debe guardar los datos. Para el File System esto es quitar de memoria la
estructura que tenía dicho archivo representándolo, y actualizar los nuevos datos guardados.
Leer un archivo implica ir a buscar los datos que contiene, que están en el File System, de alguna
manera persistidos en algún dispositivo mecánico o electrónico, y traerlos a memoria para
poder utilizarlos.
Para escribir, debo haber traído algo, lo modifico y lo guardo, o es algo nuevo que no tenía
contenido. Agregar contenido implica múltiples operaciones para que eso que teníamos en
memoria persista en disco en alguna parte del File System y que sea de manera óptima para
que, si necesitamos agregar más información, o si necesitamos ir a buscarlo, sea lo más rápido
posible.
Reposicionar es la operación que utilizamos para ir a cierta parte del contenido del archivo,
sin tener que pasar por todo el contenido inicial, calculando a donde ir según algunos
parámetros.
Truncar es una operación que agrega contenido al final de un archivo.
78
Lucila Canalini
Apertura de archivos
Modos de apertura. Lectura, escritura, append (agregar al final, no permite modificar
el contenido anterior, únicamente ampliarlo), etc.
Tabla global de archivos abiertos. El Sistema Operativo trabaja con esta tabla, que es
una estructura auxiliar para trabajar con los archivos. Para que pueda trabajar el
Sistema Operativo, los archivos deben estar abiertos, por eso es que esta tabla es
de archivos abiertos. Esto implica ir a buscarlos a disco y ponerlos en memoria. Si no
están en memoria, el Sistema Operativo no lo puede ver, por lo que no puede trabajar
contra los archivos estando en disco, como lo hace con procesos.
En esta tabla se tiene una entrada por cada archivo abierto en el sistema, ya sea
del lado usuario o del lado kernel. Esta tabla contiene el contador de aperturas, el
tipo, y la fecha de modificación. No contiene el puntero de archivo. El puntero
actual es específico y diferente a cada proceso que abre el archivo. Debe formar parte
de la tabla de archivos por proceso.
La tabla se utiliza a medida que se abren y cierran los archivos. No es necesario
persistirla en disco ya que en caso que se desmonten el FS, no quedarán archivos
abiertos del mismo.
Tabla de archivos abiertos por proceso. Por cada proceso tenemos una tabla de
archivos abiertos. Se reduce a aquellos archivos que se fueron abriendo por cada
proceso, en el modo que fuese. Lleva una cuenta de la cantidad de aperturas que tuvo
un archivo.
Cada una de las entradas es un File Control Block, que es un bloque de control
de archivos que tiene los atributos del archivo, los permisos, etc. A su vez, es un puntero
a la tabla principal de la entrada de ese archivo. Internamente, la tabla de archivo para
un proceso, tiene un puntero que indica donde está parado dentro de ese archivo, y
también indica el modo de apertura.
Estas dos tablas se van completando a medida que uno abre y cierra archivos. Cuando uno
ejecuta la operación “abrir”, indica completar esta tabla global de archivo, para que mi Sistema
Operativo y los procesos tengan a mano los atributos de cada uno de los archivos que abre. Esto
es porque si no, debe ir a buscar los atributos al disco, que es mucho más costoso que buscarlos
en memoria.
Tipos de bloqueos
Los archivos pueden estar abiertos por más de un proceso, por lo que debe haber bloqueos
para que no acceda más de un proceso al mismo tiempo, a menos que solo se pretenda hacer
lectura.
Es parecido al tema de sincronización (los mutex). Pero, a diferencia de los mutex, con los
bloqueos no debo bloquear todo el archivo, sino que con bloquear la porción de archivo que
necesito, es suficiente. Por lo tanto, permite las múltiples operaciones sobre un mismo archivo,
siempre y cuando las partes bloqueadas no sean las mismas, y dos procesos no intenten hacer
operaciones sobre la misma porción. Entonces, si las operaciones son sobre dos porciones
bloqueadas distintas del archivo, podrán acceder al mismo tiempo tranquilamente.
79
Lucila Canalini
Tipos de archivos
En el sistema en general, para lo que es file system, tenemos distintos tipos de archivos. El
Sistema Operativo tiene algunos tipos de archivo que le permite trabajar de diferente manera,
y le permite presentar diferentes vistas al usuario, o le permite generar diferentes operaciones.
Archivos regulares (de texto o binarios): Aquellos que contienen estructuras, donde
almaceno la estructura de dato y el archivo tendrá iguales estructuras de datos iguales,
pero con diferente información almacenada en sí misma.
Son los que en general maneja un usuario común y corriente, permitiéndole
trabajar y persistir datos en el file system. Se pueden abrir con aplicaciones del sistema
o propias del usuario.
Ejemplo: Una imagen, un gif, un pdf, un Word.
80
Lucila Canalini
Tipos de accesos
Cuando uno abre un archivo, tiene que poder procesarlo. Se pueden leer de distinta forma.
o Secuencial: Se lee desde el principio del archivo hasta la posición que yo requiero.
Podría tranquilamente ir a alguna parte del archivo, pero se necesita alguna
información para poder hacerlo, haciendo algún cálculo, por lo que igualmente tendré
que recorrerlo completo.
Manejo de rutas
Para poder hablar de rutas hay que hablar de directorios.
Cuando trabajamos en cualquier sistema, sabemos que
hay carpetas, que son archivos de tipo especial, de tipo
sistema operativo, que contiene un listado de otros
archivos y directorios posiblemente. Nos permite hacer
una clasificación, poder separar, poder colocar dentro de
diferentes directorios diferentes archivos, y nos permite
encontrar el archivo dentro del File System.
Un directorio entonces es un tipo de archivo que
adentro tiene una lista con el nombre del archivo, un
indicador hacia el FCB si existe, y algún dato o atributo
extra que uno puede ver cuando abre la carpeta y ve
los archivos. Estos datos le permiten al Sistema Operativo
leerlos rápido sin tener que ir a buscar el archivo
propiamente dicho para mostrar ese tipo de información.
Ruta absoluta: Aquella en la cual uno lista donde está a part ir del directorio raíz.
Si estamos parados dentro de la carpeta “Finales 2017 diciembre”, y queremos obtener la ruta
absoluta, muy probable es que, como suelen estar dentro de la carpeta de usuario dentro del
File System, la ruta será /home/*nombre de usuario*/finales/2017/diciembre. Por lo tanto,
ruta absoluta hace referencia al archivo con respecto al directorio raíz del sistema.
Ruta relativa: Es relativa a un punto. Tendré que estar parado dentro de otro
directorio, para poder trabajar con rutas relativas. Puedo trabajar con una ruta relativa
a un directorio en particular, no necesariamente el directorio raíz.
Si tomamos el archivo de antes y quiero el archivo que está dentro de la carpeta marzo, puedo:
hacer referencia de la ruta absoluta desde el directorio raíz, o hago referencia directamente con
respecto al directorio anterior.
81
Lucila Canalini
Siempre habrá un directorio de referencia, que puede ser el raíz o no. Es importante cuando
se hace un cambio de ubicación, para no tener que modificar los accesos directos. Va de acuerdo
al Working Directory, que es donde estamos parados.
Habitualmente decimos que dos archivos no pueden tener el mismo nombre. Para diferenciarlo
de otro, el sistema operativo toma como nombre la ruta absoluta, entonces si no se encuentran
en la misma ruta, pueden llamarse igual.
Directorios
Lista de archivos donde se asocia el nombre de ese archivo con atributos. Esto nos da la
particularidad de que los directorios son archivos y su contenido interno es un listado de los
archivos que contiene, los cuales también pueden ser directorios.
Los atributos más importantes son el nombre, la identificación para el usuario, y el id,
identificador interno propio del Sistema Operativo para ese archivo.
Los directorios tienen operaciones particulares para poder trabajarlos: búsqueda de un
archivo, crear un archivo, renombrar un archivo, borrar un archivo, listar un directorio (saber
todos los archivos que tenemos, en forma de árbol, viendo directorios, subdirectorios, y los
archivos finales), recorrer el File System.
Crear un archivo dentro de un directorio, del tipo que fuese, implica una operación sobre el
directorio. A este se le agrega la referencia al archivo nuevo que hago, y a su vez le pone una
referencia al FCB dentro del File System, la fecha de creación, entre otros datos que se crean en
ese momento.
Con respecto a las búsquedas, los directorios permiten operar en búsqueda para poder traer
todo el contenido y que sea mucho más rápido y no tener que ir buscando uno a uno.
En general, el Sistema Operativo, cuando va a leer un directorio, lo abre, y al abrirlo le da una
entrada dentro de la tabla de archivos generales que tiene. A su vez, levanta los datos que
componen al directorio (el listado de archivos y directorios internos), y para poder operar con
las operaciones mencionadas (buscar, crear entrada nueva, borrar, hacer listado, etc.), tiene que
trabajar con una estructura afín. Esto le permite una búsqueda mucho más rápida.
En general, se utilizan directorios de formato árbol o en formato grafo. Las hojas suelen ser
archivos regulares, o del tipo que fuese, o podrían ser algún tipo de directorio.
82
Lucila Canalini
Los nodos internos son directorios y las hojas son archivos finales (o también podrían ser
directorios). Los arboles no pueden tener ciclos, por lo que, si lo represento como un árbol, no
podría compartir de ninguna manera un archivo que está dentro de una rama que no
corresponde a una rama actual. Por eso aparecieron los de forma de grafo general. Esta es una
estructura similar a un árbol, pero con accesos directos.
Los File Systems tienen dentro de su estructura un bloque llamado Master Boot Record, con
cierta información que le permite al Sistema Operativo poder leer el File System en general,
sabiendo qué estructuras tiene adentro. El Sistema Operativo sabe levantarlas, juntarlas y
poder trabajar en memoria con este File System.
Protección
Cuando tenemos sistemas donde somos usuarios y se permite a una única persona, no es tan
útil. Se puede utilizar la protección de acceso total. Pero si al sistema se pueden conectar varias
personas, como lo es un servidor, sí.
Para esto, existen distintos tipos de protección:
Acceso total: Cualquiera que prenda la máquina y acceda lo pueda leer.
Acceso restringido: Solo el que lo creó tiene acceso a tal.
Acceso controlado (permisos de acceso): Quien brinda la restricción es aquel que lo
crea. El creador lo lee, lo escribe y lo ejecuta, y además le da permiso a quienes pueden
acceder. Entonces, si más de una persona tiene acceso, puedo elegir una restricción
especifica. Sacar el permiso de lectura, escritura, y/o ejecución a dicho archivo a
usuarios específicos, y a otros darles dicho acceso. Según el sistema en el que
trabajemos, existen distintos tipos de permisos de accesos:
83
Lucila Canalini
Unix: Creo el archivo, por lo que tendré acceso, elijo un grupo (limitado) al que le daré acceso,
y al resto no le daré acceso. Tengo la posibilidad de darle ciertos permisos a algunos, ciertos
permisos a otros, pero no tendré algo más granular. Sólo permite definir permisos para el
propietario, un solo grupo y el resto de los usuarios que no sean el propietario y no formen
parte del grupo, no tendrán permisos.
Matriz de accesos: Por cada archivo o directorio en el sistema, y por cada usuario, da un tipo
de protección. Es muy granular porque tengo un permiso para cada usuario por cada archivo,
pero es imposible de mantener. Ocupa mucho espacio la matriz de acceso, porque una matriz
de acceso hay que persistirla. No se puede implementar.
Listas de control de acceso (ACL): Linux la implementa como complemento al tipo de usuario
“grupo y otros” (tipo Unix). Hace una lista de control de acceso, conformada por nodos en los
cuales dice el usuario, el permiso, y nada más. Por lo cual sobre los archivos habrá una
combinación de tipo Unix y un ACL. Esta es una lista enlazada. Permite personalizar los accesos
para los usuarios. Le daré permisos a los usuarios que yo requiero que hagan cada tipo de
acceso (lectura, escritura o el que fuera). Es ilimitada. Permite algo más granular que el tipo
Unix y sin tener que implementar la matriz de acceso previamente mencionada. Cuando uno va
a leer un archivo, y lo trae de memoria, trae esta lista, la cual no implicará leer mucha más data.
Contraseñas: El común y corriente. La contraseña tendría que estar almacenada dentro del
disco, el algún lado que no sea dentro del archivo. Es más controversial. Ya no se usa este tipo
de protección, sino que la protección va de la mano del usuario.
Disco lógico
El File System es un disco lógico que está compuesto por bloques lógicos. Un bloque es aquella
porción que forma al archivo. Es una representación de una cantidad de un tamaño de bytes a
los cuales el Sistema Operativo opera.
A los bloques puedo leerlos, reservarlos, escribirlos. El último bloque que almacena datos de un
archivo, no tiene por qué estar lleno, por lo tanto, puede tener fragmentación interna. Los
bloques adentro pueden tener cadenas de caracteres, registros.
Los bloques lógicos son de tamaño fijo y cada uno puede contener información sobre un
solo archivo. Algunas implementaciones permiten el uso de bloques de tamaño variable y de
tamaño variable y expandible.
84
Lucila Canalini
Un archivo está compuesto por uno o más bloques. Todo lo que se vaya a almacenar en un disco
lógico ira a parar dentro de un bloque. El disco lógico toma a todos los bloques como si fueran
un array y sabe que ese volumen está compuesto por tales bloques de datos.
El Sistema Operativo lo utiliza para abstraerse de lo que son las implementaciones propiamente
dichas del File System, del disco físico.
Cuando uno escribe en un disco o en un File System, siempre se hace de a bloques. Si quiero
modificar un byte de un archivo, tengo que encontrar el bloque, modificar el byte en memoria,
y luego modificar el bloque entero.
Partición
Los dispositivos de almacenamiento son una tira de bytes. La partición será una porción de
bytes.
Una computadora para poder leer un dispositivo que tiene particiones, necesita una tabla de
particiones. Esta tabla está en el primer sector del dispositivo e indica que de qué posición
(byte) hasta cuál ocupa la partición. Así, se puede hacer referencia a las particiones.
Las particiones en sí no sirven de nada si no le doy una forma. Para esto, se lo formatea
(FAT, UFS, etc.), con un tipo de File System, y ahí se le da sentido al conjunto de bytes. Esto es
porque se les da un formato a ciertos bytes en cierta posición. Una vez que se le da formato a
una partición, se convertirá en volumen.
85
Lucila Canalini
Entonces, una partición con un formato específico de File System es un volumen. Los File
Systems internamente contienen estructuras a grandes rasgos para que los sistemas operativos
los puedan trabajar sin ningún problema.
o Bloque de control del archivo (FCB): Una estructura que nos permite almacenar
archivos (con sus datos, información persistida) y todos los metadatos de los archivos
(fecha de creación, modificación, ultimo acceso, permisos, etc.). Los FCB pueden estar
asociados a un solo archivo.
Para las implementaciones en que los FCB están definidos desde la creación del File
System, podrían haber FCB asociados a ningún archivo.
o Bloque de control de volumen: Está dentro de cada uno de los volúmenes. Contiene
información administrativa y le permite al Sistema Operativo saber, cuando se lee dicho
volumen, cuántos bloques de datos están escritos, cuáles son, cuáles bloques están
libres, cuántos, qué cantidad de archivos tiene, qué cantidad de FCB están disponibles,
etc. Sirve para la administración en general para que el Sistema Operativo pueda operar
con el File System.
86
Lucila Canalini
En un sistema se puede crear una cantidad limitada de archivos, aunque fuesen vacíos. Esto es
porque tenemos un número limitado de FCB para poder manejarlos.
Estructura de directorios: Para poder acceder a los directorios, hay que ponerlos en
algún lado. Entonces, cuando se monta el File System, algunos sistemas los ponen por
fuera del File System actual (como Windows), o montan su volumen dentro de algún
directorio del File System actual (como Linux y Unix), permitiendo operar a través de
ese directorio con la estructura de directorios que trae el volumen que se acaba de
montar.
Tabla o lista global de archivos abiertos.
Tabla o lista de archivos abiertos por proceso.
El File System donde está montado el propio Sistema Operativo es el que arranca cuando
arranca el sistema, siendo el primero que se carga. Está montado dentro de un volumen con las
estructuras, y cuando carga la tabla de montaje, o las entradas que tenga (porque puede estar
formado por más de un volumen), va a tener las propias de su sistema.
Implementación de directorios
Los directorios tienen su manera específica de operar. A medida que se lee un directorio, se
abre el archivo que corresponde al directorio, se lo carga en memoria y se lo carga en una
estructura de las siguientes (es decir, se puede representar en memoria los directorios de las
siguientes formas):
Lista lineal: No tiene ningún tipo de orden, por lo que es muy costoso si la lista es
grande porque hace búsquedas secuenciales. Bajo rendimiento.
Si se borra, se puede ir a buscar el archivo, y se quita el nodo.
Lista ordenada: Cuando quiero agregar un nuevo nodo, debo buscar en qué posición
tengo que agregar el nodo, para mantenerla ordenada. También es costoso.
87
Lucila Canalini
Si se borra, el borrado es lógico. Se hace una marca de que no se utiliza más, y cuando
se quiere agregar un nodo que iría en ese lugar, se reutilizará el nodo con la nueva
información.
Tabla de hash: Hay una función unívoca en la que ingreso un nombre y me devuelve la
posición en la tabla. La función tiene una cantidad finita, por la que debo saber el tamaño
del directorio, y debo limitar la cantidad. Si hay colisiones, se complica.
Métodos de asignación
El Sistema Operativo ve a los archivos como un bloque de datos, además del Control Block, que
son los metadatos de dicho archivo.
Los archivos los mapea en su totalidad dentro de los bloques de datos, que básicamente tienen
un tamaño fijo. Al mapear un archivo, se debe particionar en bloques. Al dividirlo en estos
bloques fijos, para este ejemplo, ocupa cuatro bloques.
Se puede ver que en el cuarto bloque al final, no lo completa
totalmente (padeciendo fragmentación interna). Este lugar no
es reutilizable por otro archivo, porque solo un archivo puede
utilizar el conjunto de bloques que le fue asignado.
Si tengo que modificar una línea del main.c, desde la vista del
usuario, se modifica la línea y listo. Pero cuando se guarda,
internamente el Sistema Operativo, actualiza en memoria el
bloque correspondiente a la línea modificada, y lo baja a disco,
para actualizarlo en el bloque correspondiente que fue
asignado al disco lógico. Este disco lógico se corresponde con
alguna parte de un disco mecánico o un disco electrónico.
El Sistema Operativo asigna bloques de la manera más eficiente para poder utilizarlos de la
mejor manera posible, sin perder espacio.
El main.c es un tipo de archivo regular. Si uno lista los
directorios, verá un listado como el siguiente (próxima
página). Esto es porque el Sistema Operativo lo almacenó
dentro de bloques como un listado con el nombre, tipo de
archivos, y el id que es un puntero al FCB dentro del volumen.
El tercer bloque no está completo, por lo que, si yo sigo
agregando archivos, o moviéndolos de otro directorio a este,
se agregaran entradas, una debajo de la otra, hasta completar
el bloque. Si tengo el tercer bloque completo y quiero agregar
una entrada más, el Sistema Operativo buscará un bloque
vacío, le asignará al directorio /home/user un bloque nuevo, y
agregará una entrada para este archivo.
88
Lucila Canalini
Cuando creo un archivo debo darle un nombre y asignarle un FCB. Este último tiene que poder
hacer un seguimiento y dar referencia a los datos que va almacenando. Con esto, da una noción
de que necesito tener una manera de recuperar esos bloques que componen al archivo.
Asignación contigua
Uno cuando crea un archivo, crea una entrada en el directorio, y busca el primer bloque
disponible (que no esté utilizando otro archivo), e intenta asignárselo al archivo recién creado
mediante un FCB.
Entonces, asignación contigua, cuando lo guarde, buscara la cantidad de bloques necesarios
para guardarlo, y utilizará los primeros que estén libres y contiguos. Una vez encontrados,
recién ahí asigna los datos en los bloques.
La entrada de directorio para esta asignación incluye el nombre de
archivo, el número de bloque en donde empieza, y cuantos bloques
ocupa.
La ventaja de esto es que cuando se necesita recuperar el contenido
del archivo, es fácil porque al leer la entrada de directorio, se en que
bloque debo pedir y cuantos bloques más tengo que traer a memoria
para poder visualizarlo. A su vez, con algún calculo extra, y sabiendo
el tamaño de los bloques, podría posicionarme en alguna parte del
archivo y el acceso directo estaría disponible.
Sin embargo, si tengo que agregar información al archivo que
sobrepasa la cantidad de bloques reservados, pero el siguiente bloque está ocupado, no podré
agregar esta información. Es decir, solo podré agregar cosas si existen más espacios contiguos.
Además, tiene problemas del lado del Sistema Operativo, relacionado a cómo va a buscar un
espacio donde entre.
Este tipo de asignación padece fragmentación externa porque estará llena de bloques libres y
ocupados intercalados. Cuando se quiera guardar un archivo, habrá espacio libre, pero los
bloques contiguos no serán suficientes para guardarlo, por lo que no se podrá.
89
Lucila Canalini
Indexada
Es el tipo de asignación que utiliza UFS. Es una mejora de la asignación anterior. Dado un
archivo, le extraigo toda la metadata y la pongo en un único bloque. Tendré un bloque índice o
bloques que solo tendrán punteros a bloque de datos. Se tienen de forma secuencial, por lo que
puedo hacer el mismo recorrido que hacía con la enlazada, sin tener metadata dentro de los
bloques de datos.
Si bien mejora el tener los bloques de datos libres de tener metadata,
y se utilizan completos sin esta, tendré bloques de índices para cada
archivo. Este bloque índice estará asociado al archivo y a nada más.
La entrada de directorio será el nombre y la referencia o número de
bloque correspondiente al bloque índice.
Si hay un archivo con un único bloque asociado y con una única
entrada, habrá fragmentación interna en general para este bloque, y
tendré un bloque índice solo para tener una entrada y el resto del
bloque lo desperdicio. No sufre fragmentación externa porque cualquier bloque libre puede ser
asignado a un archivo.
Si se tiene un archivo con más bloques asignados, con lo cual un bloque índice no alcanza, habrá
que encadenar bloques índices. Así, el ultimo índice de un bloque de índices encadenados, va a
ser el puntero al siguiente bloque índice. Por esto se tendrá un listado de bloques índices, y el
listado que esta internamente referenciado por los números de bloques dentro del bloque
índice.
Es adecuado para el acceso directo y para el secuencial. Si se daña un bloque, no pasa nada,
puedo leer el resto del archivo. Sin embargo, requiero espacio adicional: no solo para datos,
sino que también para los bloques índice.
90
Lucila Canalini
2. Asignarle bloques requeridos: Tengo que llevar el FCB a memoria para luego
empezar a trabajar con los bloques de datos. Para esto, se abre el archivo y se agrega en
las listas de archivos abiertos. En esta tabla se le agregará la entrada y se pondrá el count
(cantidad de veces que fue abierto) en 1. El proceso que está escribiendo el archivo va
a tener en su tabla de archivos una entrada con este FCB. Se obtienen los bloques libres,
y asignarlos bloques al archivo. Para asignar los bloques de datos voy a tener que
agrandar el tamaño del archivo. Para esto, el Sistema Operativo lo que hace es truncarlo.
91
Lucila Canalini
Recuperación
Puede pasar que el procedimiento de escritura se corte por la mitad, o que maten al proceso
justo cuando estaba guardando.
Si hay alguna falla cuando hay un proceso de escritura, el archivo que se estaba bajando al
dispositivo que lo iba a persistir, en general termina corrupto. Cuando pasa esto, el archivo no
se podrá recuperar, por más que haya mecanismos de chequeo. Lo que sí se puede hacer es que
uno los puede excluir como corruptos. Para eso, el sistema corre algunos mecanismos para
detectar errores.
92
Lucila Canalini
Área de swapping
En general es un archivo. En Linux se trabaja como una partición. Es un espacio con un formato
(es un volumen en el fondo). Se usa generalmente para hacer el swapping de lo que es la
memoria virtual. Tiene un tamaño determinado que podría llegar a expandir. No tiene ningún
tipo de formato.
Las particiones tienen un tamaño fijo. Cuando uno define un File System dentro de una
partición, File System estará atado a ese tamaño y si se quiere agrandar la partición, se puede
hacer con alguna herramienta. Deberá eliminar la partición contigua y el espacio libre deberá
tomarlo la partición actual, pero a su vez no alcanza porque el File System no va a reconocerlo
a menos que se haga un resize.
Con respecto al swap, funciona de la misma manera. Podría expandirse o no. Podría hacerse en
una partición o en un archivo.
Si se hace en una partición aparte, lo que nos da es que, si tenemos este tamaño fijo, sabemos
que puede trabajar internamente con bloques de datos continuos. Es un formato File System
propio que maneja el Sistema Operativo, y lo utiliza para hacer swap de páginas de procesos
que no se están usando memoria, entonces lo baja a esta partición. Esto lo hace porque es más
fácil que hacer una búsqueda de que bloque tiene tal parte.
El archivo va a recibir dentro del propio File System donde está levantado el propio sistema
operativo. El archivo es mucho más fácil de expandir el tamaño.
En Windows se utilizan archivos. Una de las desventajas que tiene es que para poder acceder a
estos archivos hay que hacer llamadas al sistema que afectan al mismo File System.
93
Lucila Canalini
El Boot Sector tiene información sobre el volumen. Esta información es el nombre, tipo,
cantidad de tablas que tiene de FAT, cantidad de Clusters que ocupa la FAT, tamaño de los
punteros –las entradas- de la FAT.
94
Lucila Canalini
La FAT es una tabla en la cual cada entrada es un puntero a cada uno de los Clusters dentro del
volumen. Entonces, si tengo 1000 Clusters, la tabla tendrá 1000 entradas. Esta es una tabla para
poder encontrar los archivos.
Los archivos están plasmados como entradas en la tabla de FAT y el directorio. Si pierdo las
tablas de FAT no tengo manera de poder seguir los bloques a un archivo, por más que vea la
entrada en el directorio. Se tendrá una o más copias. Solo se utilizará la primera, mientras que
las copias están solamente por si le pasa algo a la principal. Cada cierto tiempo se actualizan
dichas copias.
Dentro de los directorios de FAT hay un listado de archivos y directorios que contiene. Las
entradas del directorio son: tipo de archivo, nombre y extensión, primer Cluster archivo,
tamaño. Los directorios se trabajan distinto a otro tipo de archivo (archivos regulares).
La cantidad de entradas que puede tener un bloque que pertenece a un archivo de directorio,
se calcula haciendo el tamaño del bloque dividido por la cantidad de entradas.
No se tiene un FCB por cada archivo. Esta implementación de File System no trabaja con una
estructura para cada archivo, sino que es el directorio el que me da todos los datos del archivo.
Con el primer Cluster del archivo y combinado con la FAT de la tabla puede obtenerse.
Los bloques de datos pueden soportar archivos, pueden tener tamaños que van desde 512
bytes a 64 KB, y el tamaño del bloque.
Si el archivo ocupa 2000 bytes y el tamaño de Cluster (bloque) es de 1kb, entonces para saber
cuántos Clusters debo leer para leer todo el archivo, debo hacer tamaño del archivo/tamaño
del Cluster, es decir, 2000/1024, y el resultado me dirá el máximo de Clusters que habrá que
leer. Cuando se lee un archivo, se mira la tabla FAT.
95
Lucila Canalini
Cuando quiera leer el archivo arc.txt, va a ir al Cluster 7, y para saber cual tiene que seguir
leyendo, se fijara en la tabla. Ve que tiene que leer el 6, y cuando lo lee, ve que no hay más por
leer, por lo que se termina. El fin está marcado con todos 1s, o con F si se lo ve en hexadecimal.
El tp.c empieza en el Cluster 5, va a la tabla, ve que el próximo Cluster es el 4, entonces como le
sigue en datos, se lee el bloque 4 luego de levantarlo, y leo dentro de la tabla cual le sigue, veo
que es el 9, lo levanto, y me fijo en la tabla si necesito leer el próximo, y me dice que no hay más
para leer. Entonces, levante estos tres Clusters que, según el tamaño del archivo, son suficientes.
Para este archivo tp.c, de tamaño 3000, si usa 3 Clusters, tendrá como espacio 3x1024 por ser
el tamaño del Cluster 1kb. Entonces, tendrá un tamaño de 3072 bytes, pero solo necesita 3000,
por lo que ahí notamos la fragmentación interna.
Si, por ejemplo, para el archivo arc.txt, se corrompe el bloque 7, podré de todas formas leer el
bloque 6, por lo que tenemos una mejora a la asignación enlazada, porque por más que esté
corrupto, podre al menos salvar parte del archivo.
Cuando se crea la tabla, es decir, cuando se formatea el sistema, solo estarán ocupados los
Clusters respectivos a la estructura administrativa, mientras que los que están disponibles, los
marca como libres. El Master Boot Record, que maneja el volumen, por ejemplo, ocupa uno o
dos Clusters. Los Clusters se empiezan a enumerar a partir del primero que esté disponible para
almacenar archivos o directorios.
Cuando se quiera asignar un bloque, se debe mirar la File Allocation Table para ver si la entrada
está en libre o está con error. La tabla se encarga de manejar tanto los bloques libres como los
ocupados. Arma una cadena de Clusters. Si hay algún bloque que tiene un error porque al
Cluster no se le puede marcar nada por algún problema del disco, le permite no elegirlo a la
hora de asignarlo.
Es fácil de manejar porque se puede leer archivo de manera indexada, con solamente hacer un
seguimiento de los Clusters indexados en la tabla FAT.
Tipos de FATs
Si la tabla de la FAT me da una entrada por cada Cluster que tiene el sistema, tengo que poder
referenciar a todos los Clusters dentro del volumen.
FAT8: Es la FAT común. Quiere decir que tiene un puntero de 8 bits. Puedo tener
2^8 = 256 entradas.
FAT16: Punteros de 16 bits. Ocupare 4 bytes por cada uno de los punteros. Me da 2^16
entradas.
FAT32: Punteros de 32 bits. Solo se usan 28 bits para el puntero. Quien implemento
FAT32 se comió 4 bits de los 32 para almacenarlos por alguna cuestión. Algunos libros
dicen que es para manejarse dentro de Clusters muy grandes. Cada entrada mide 4
bytes. Por lo que la tabla, solamente, pesará 1 GB.
96
Lucila Canalini
Los tamaños de la entrada, es decir, la cantidad de bytes que tengo, me dirá la cantidad de
Clusters que podre referenciar.
Si el Cluster, por ejemplo, tiene tamaño de 1kb, y trabajo con FAT8, quiere decir que no podré
trabajar con File System con más de 256 KB.
Desventajas
FAT no tiene seguridad.
No gestiona los espacios libres aparte, sino que lo hace la misma FAT. Lo malo de esto
es que sí o sí hay que recorrer toda la tabla hasta encontrar una posición libre (de todos
ceros).
Como no hay FCB, no tengo una estructura en la cual agrupe por cada uno de los
archivos los datos (atributos de creación, modificación, último acceso, permisos).
No tiene backup.
UFS trabaja con grupos de bloques. En una partición se graba un bloque de arranque con cierta
información sobre todo el grupo de bloques, es decir, información global sobre el volumen. Cada
uno de los bloques tiene el mismo formato de estructura interna, pero con diferente
información.
El súper bloque, al igual que el Boot Sector, tiene el tamaño del bloque, el nombre del File
System, la cantidad de bloques libres, estados (correcto/incorrecto). A su vez, llevara ciertas
métricas de cantidad de nodos ocupados o libres, en que bloque se encuentra el directorio raíz.
El descriptor de grupos tiene información sobre los grupos, y a su vez tiene punteros a los
bloques siguientes. El súper bloque y el descriptor de grupos es igual en todos los grupos.
97
Lucila Canalini
El bitmap de bloques, será uno o varios bloques que estarán formateados en formato bitmap.
Todos los unos y ceros que tiene a dentro marcarán qué bloque está libre y qué bloque está
ocupado dentro de los bloques de datos. Por el otro lado, el bitmap de nodos, tiene la misma
función, pero en lugar de hacerlo con el bloque de datos lo hace con la tabla de nodos.
Cada archivo del sistema tendrá asociado un FCB, a diferencia de FAT que no tiene File Control
Block. El FCB tendrá los atributos del archivo y los punteros a los bloques de datos.
La entrada no tiene un tamaño fijo.
Los directorios en UFS ahora, a diferencia de FAT, perderán cierta información, que ahora
estará almacenada en FCB. Es por esto que, al no tener tanta información, se reducen. Los
directorios tienen un formato como el siguiente: el nombre de identificador del FCB, el nombre
del archivo, y un indicador más que será el tipo, para identificar si es directorio, archivo regular,
socket, etc. Este número de identificador de nodo nos servirá para buscar el nodo que le
corresponde al archivo con dicho nombre.
Inodos
Son el FCB del File System y existe uno por cada archivo. La entrada de la tabla de archivos
globales para el archivo que traigo de memoria, será un inodo representado en memoria, y será
similar (no igual) al que está almacenado en el File System.
Un inodo tiene un identificador que se corresponde con el id que está en la entrada del
directorio. Dentro del FCB, que en este caso es el Inodo, hay muchos más datos que el directorio
en FAT no tenía. Tales como el propietario, el tamaño del archivo, los permisos.
El tamaño del archivo podrá hacer varios cambios dentro del archivo. Al tener un FCB y no tener
una limitación en la entrada de directorio, se puede jugar con la cantidad de campos dentro del
inodo, y nos permite tener tamaños de archivo muchos mayores. En el FCB destinamos el
manejo de archivos a esta estructura, la cual tiene un tamaño fijo (en general, de 128 bytes).
98
Lucila Canalini
Si tengo este tamaño fijo, y tengo entradas de 4 bytes para cada puntero de datos, habrá un
problema.
Los punteros son los números de bloques donde están los datos. Se dicen punteros, pero en
realidad tienen los números asignados.
El inodo utiliza un sistema de punteros a demanda utilizando bloques de datos. Se maneja
como el sistema de enlazado indexado. Mientras no se necesiten los punteros, no se usan.
Trabaja con tipos de punteros en el inodo:
Punteros directos: Apuntan a un bloque de datos directamente.
Punteros indirectos: Apuntan a un bloque de punteros. Pueden ser simples, dobles,
triples.
La cantidad de punteros que puedo tener por cada bloque dependerá del tamaño. Si divido el
tamaño del bloque por el tamaño de cada puntero, y tendré la cantidad de punteros que
tendré. Si son a bloques índices o a bloques de datos, dependerá de donde estén.
Permite trabajar con bloques de datos chicos, y no perderé ningún bloque de dato indexado,
por tenerlo en el inodo.
El tamaño máximo teórico de un archivo, no está limitado por el tamaño del directorio como en
FAT. Este se calcula con los bloques directos totales que puede llegar a almacenar a través de
un inodo.
99
Lucila Canalini
Soft LINK / Symbolic LINK: Es un archivo que en su contenido es una ruta a otro archivo, es
decir, una ruta de directorio. Nos permite poder compartir un archivo a través de soft LINK, y
acceder al archivo que está en otra parte, mediante la apertura del archivo actual. El Soft Link
no está acoplado al File System.
Cuando se crea, nos genera una entada en el directorio con el nombre que asignamos, tendrá
asignado un inodo, y al inodo se le agregara en sus datos el contenido de la ruta que se le aporto.
Por su naturaleza, tiene una ruta al archivo, por lo que, si borro el archivo original, la ruta
apuntara a algo que no existe. El sistema no actualiza ese link.
Ejemplo:
Si quiero crear dentro de /usr un Soft LINK a tp_v2.c, que tiene el inodo 20, hago referencia a la
ruta del archivo con los comandos correctos y se creara una entrada en el directorio /usr. Se
creará un archivo que tendrá otro id en el FCB. Internamente, dentro del inodo, en uno de los
tantos atributos, se aclara si es Soft Link o Symbolic Link. En el primer bloque de datos se asigna
la ruta.
Esto nos muestra que cada vez que tenga que acceder al archivo, tendrá un doble acceso a disco.
Esto es porque hay que buscar el inodo (el 33) almacenado en el File System, traerlo a memoria.
El Sistema Operativo se percata de que es Symbolic LINK. Ve la ruta y con esta ruta va a buscar
el inodo correspondiente al archivo que está en esta ruta. Así, tenemos dos accesos al archivo.
Si esto se hace con Hard Link, en lugar de 33 veríamos un 20, y se tendría un contador.
100
Lucila Canalini
Hard LINK: Es una marca dentro del inodo (del FCB) y se maneja como referencia al archivo.
Nos permite trabajar con una copia del archivo, que no realmente es el archivo.
Cuando se crea, crea una entrada al directorio que aportamos, y agrega un inodo que
corresponde al archivo original al que estoy apuntando. La herramienta le aumenta el contador
de referencia hacia el archivo a dicho inodo. Por lo tanto, no tenemos un archivo propiamente
dicho, sino que tenemos una referencia al archivo original, sin tener problemas de pasar por
otro archivo intermedio.
Si elimino el archivo, la persona a la que le compartí el archivo, podrá acceder igualmente. Esto
es porque la operación de borrarlo es descontar el contador de referencia que tiene asociado el
archivo. A menos que esté en cero, no se borrará.
Ejemplo:
Si yo quisiera crear en /usr un Hard Link de tp_v2.c y le agregará el inodo igual a 20. Por lo
tanto, será una referencia al FCB dentro del File System correspondiente a ese archivo.
Entonces, no se pasará por un archivo intermedio. Lo busca ahí directamente.
Trabajan internamente dentro del File System, no hace referencias a través de directorios, y no
se pueden hacer Hard LINKs a archivos que están montados dentro de otro File System. Esto es
porque no pueden trabajar con estructuras externas, por más que sea FAT o Extended.
No podemos saber cuál es el archivo original. Lo único que tendremos es el contador. Si
obligamos que este está en cero, entonces es porque no hay ninguna referencia a ese inodo, y
se puede eliminar.
101
Lucila Canalini
Ejemplo FAT:
La FAT 2 es una copia de la FAT 1 por seguridad. Esto es porque en la FAT están los bloques,
que se pueden dañar, y no podré leerlos. Pero si tengo una copia, puedo recuperarlo. Por defecto
se crean dos FATs (una copia), pero hay parámetros que nos permite elegir cuantas copias de
la FAT queremos. Mientras más cantidad de FAT más seguro será el File System, pero
igualmente es una estructura grande que ocupa espacio.
El directorio Raíz es por el que accederé a mis bloques. Si quiero saber lo que hay en dir1, tengo
que buscar el bloque 3 y ver lo que tiene adentro, porque indica que el contenido está en el
bloque 3. Cuando vemos el bloque 3, vemos que tiene el dir2 y el archivo2, y que
respectivamente están en el bloque 8 y en el 4.
Tanto el bloque 3 como el bloque 8 son bloques que contienen directorio: lo único que tienen
son archivos u otros directorios.
El archivo1 está en el directorio raíz, por eso tiene la R, y se encuentra en el bloque 7, o al menos
ahí se encuentra su primer bloque de datos. Para ver el siguiente bloque, busco en la posición 7
de la FAT, y encontrare el número de bloque donde sigue el archivo (y así…).
D es tipo Directorio, R es tipo regular (archivo), B representa otro tipo de archivo.
¿Cómo saber si el bloque de directorio raíz está lleno y es necesario otro bloque? Cada entrada
de directorio ocupa 32 bytes en FAT (siempre). Si tenemos bloques de 512, tengo que hacer
512/32. Esto me da la cantidad de entradas. Si tengo en un bloque esa cantidad de entradas,
entonces necesitaré uno nuevo.
102
Lucila Canalini
103
Lucila Canalini
Entrada/Salida
Los dispositivos de entrada salida son muy diferentes entre sí, a tal punto de que uno tiene un
mouse, un teclado, un disco rígido, y para el Sistema Operativo son dispositivos de E/S e intenta
tratarlos todos de la misma manera.
Toda nuestra relación con la computadora es a través de dispositivos de E/S. Son todos muy
importantes desde el punto de vista del usuario principalmente.
Tipos:
Comprensibles para el usuario: Los que el usuario puede leer y entender. Un mouse,
una impresora.
Comprensibles para el sistema: Por ejemplo, un disco, para un usuario es solo una
caja mecánica que no sabe lo que tiene, mientras que el disco se conecta con el sistema.
De comunicación: Permite comunicarse con el usuario o incluso con otros sistemas.
Un modem, una placa de red, etc.
Diferencias
La diferencia de estos tipos de entradas/salidas son: la velocidad de transferencia, el uso, la
complejidad, la unidad de transferencia, las condiciones de error, si son bloqueantes o no
bloqueantes, y si son síncronas o asíncronas.
La velocidad de transferencia en los dispositivos es muy notoria. Mientras más cerca están
del usuario más lentos son, y mientras más cerca están de otros sistemas para comunicarse son
mas rápidos. El usuario necesita ir más despacio que la computadora.
Como dispositivo lento tenemos el teclado y el mouse, mientras que los mas rápidos son las
redes y los dispositivos gráficos, que son los que pueden procesar más bits por segundo.
104
Lucila Canalini
Con respecto al uso, es variado también. Un mouse, un teclado, todos sirven para cosas
diferentes.
Un mismo dispositivo se puede utilizar para diferentes cosas. Podemos usar un mouse para leer
programas y para dibujar en una pantalla. El disco rígido puede servir para los usuarios, para
que guarden sus propios archivos, o para que el SO extienda la memoria.
La complejidad de un disco rígido, que tiene una controladora, lógica, plaquetas, cables
internos, movimientos mecánicos, discos que giran a velocidades imposibles de notar para el
ojo humano, es mucho mayor que la del mouse, que tiene una plaqueta con una bolita que se
mueve, súper simple.
La unidad de transferencia no necesariamente es siempre el byte, sino que hay dos tipos de
unidades. Una es por carácter, el caso del teclado o el mouse. La otra es por bloque, donde la
unidad de transferencia mínima deja de ser un byte, sino que la información se mueve de un
lugar a otro en tamaños más grandes. En el caso del disco se mueve en sectores. Los sectores
son por defecto de 512 bytes.
Las condiciones de errores varían porque no es lo mismo que se rompa un mouse o que se
rompa un disco.
Existen otro tipo de diferencias:
Acceso aleatorio o secuencial. En el acceso secuencial se tiene que dar en orden, como en
cintas, mientras que los discos, por ejemplo, pueden acceder a un punto específico sin necesidad
de acceder a la información anterior.
Compartible o dedicado. Puede ser usado por muchos usuarios o por uno a la vez.
Lectura, escritura, o ambos. Es decir, de entrada, salida, o ambos. Un teclado y un mouse son
de lectura, y la escritura (salida) es que se muestre en la pantalla. El disco rígido es de ambos
tipos.
Las E/S bloqueantes son cuando un proceso que está ejecutando su
código, realiza la solicitud de entrada-salida, entonces el proceso se
quedará bloqueado esperando la
respuesta. Cuando esta llegue, por medio
de una interrupción, que el proceso pasa de
estar bloqueado a estar listo, y seguirá
ejecutando.
Por el otro lado, las E/S no bloqueantes
son cuando el proceso hace la solicitud y puede seguir ejecutando
código sin necesidad de parar para esperar la respuesta. Esto trae
varias ventajas, pero la lógica del programa debe ser más compleja.
La relación con el dispositivo es síncrona cuando necesito o tengo que esperar, si o si, la
respuesta para poder continuar. Si no, no se podrá avanzar. Por el otro lado, el método
asíncrono es donde hago la solicitud, pero no necesito la respuesta inmediatamente, sino que
puedo continuar con otra tarea, y nada tiene que ver con la respuesta, por lo que puedo seguir
trabajando. En algún momento habrá que consultar si la respuesta la tengo o no.
105
Lucila Canalini
106
Lucila Canalini
procesador está constantemente viendo si está listo o no. Cuando hay mucha
información para transferir, no es la mejor técnica.
Buffering
Los buffers son espacios de memoria dentro del kernel del sistema operativo, reservado para
ciertos casos. Es un área de memoria, que no es ajena a la RAM, que almacena datos mientras
se transfieren entre disposiivos o entre un dispositivo y una aplicación.
107
Lucila Canalini
Sus dos funciones principales son que: Adapta diferencias de velocidades y adapta unidades
de transferencia.
La primera se refiere a que, por ejemplo, la computadora escribe rapidísimo lo que quiere
imprimir, mientras que la impresora tarda más en imprimirlo. Así, el proceso quedaría
bloqueado hasta que se termine de imprimir. Sin embargo, puedo escribir toda la información
a imprimir en un buffer, y poder seguir haciendo otras cosas mientras la impresora imprime.
Los buffers permiten que la información no desborde.
La segunda se refiere a que cuando quiero leer x bytes, pero del filesystem recibo más. Ahí se
adapta la información que se tiene para pasarle al usuario.
Una aplicación del buffer es cuando se hace el reemplazo de páginas en memoria virtual.
Cuando se reemplaza una página, esta se guarda en el espacio de memoria del SO. El page fault
ocurre igual, pero ahorramos el acceso a disco con los buffers. Estos tienen marcos reservados,
que nada tiene que ver con los marcos que utilizan los procesos.
La ventaja de esto es que si ya tengo todos los marcos victima agrupados, en algún momento
los puedo escribir todos juntos, siendo escrituras más eficientes, porque pueden ser
consecutivas. Además, si la página que acaba de ser reemplazada vuelve a ser solicitada antes
de escribirse en disco, me ahorro el acceso a disco, y ya lo tengo en un buffer aparte en la
memoria. Por último, evita el uso de bit de bloqueo de páginas.
Planificación de disco
Esto se refiere principalmente a los discos magnéticos. Es importante planificarlos porque si lo
hacemos, podemos tener mayor rendimiento. El disco se usa muchas veces, ya que todos
nuestros archivos, programas, Sistema Operativo, están en disco, además de ser utilizado como
memoria virtual.
108
Lucila Canalini
Estructura de un disco
Los discos pueden dar entre 90 y 120 vueltas por segundo. Si bien el giro se hace a velocidad
constante, a menos que haya algún inconveniente, el brazo es quien entrega la información.
Físicamente hay tres platos en un disco, pero lógicamente pueden ser más. Cada uno de estos
platos, en cada una de sus caras, que suelen ser dos, encontramos la siguiente estructura, donde
tenemos pistas y sectores:
Tanto las pistas como los sectores están enumerados. Por cada cara existe un cabezal, que es
quien termina realizando la operación de lectura o escritura, y, además, la transferencia.
Un cilindro es un conjunto de pistas. Un cilindro está compuesto, por ejemplo, de todas las pistas
número 10 de todas las caras. Por lo tanto, para hacer referencia a un sector particular, hay que
hacerlo de acuerdo al número de cilindro al que pertenece, el número de cabezal que hay que
utilizar para leer, y el número de sector (que es el número de sectores por pista).
109
Lucila Canalini
Planificación de disco
No se tiene en cuenta el tiempo de transferencia ni la latencia rotacional para los ejercicios,
porque son tiempos que no se pueden manipular.
Para planificar e n qué orden se leerá cada sector, existen ocho algoritmos de planificación, cuyo
objetivo de todos ellos es reducir el tiempo de búsqueda.
A medida que pasa el tiempo, los pedidos se van actualizando, por lo tanto, cada vez que me
paro en una nueva pista, aparecen nuevos pedidos. Entonces luego de atenderlos, tengo que
volver a preguntar que pedidos hay.
110
Lucila Canalini
SSTF (Shortest Seek Time First): Busca el pedido de pista más cercano al cabezal. Es
mucho más eficiente que el FIFO en cuanto velocidad. La desventaja es que sin importar
el orden en que lleguen, se atienden en el mismo orden. Por lo tanto, hay inanición.
Si se tiene dos sectores a la misma distancia de la posición del cabezal, se tiene
en cuenta el movimiento del brazo. Si el brazo estaba subiendo, se seguirá subiendo, Si
estaba bajando, se seguirá bajando.
SCAN: El cabezal se mueve constantemente hacia arriba y una vez que llega al tope
empieza a bajar, y una vez que baja, lo hace hasta llegar al tope. No es que comienza a
subir o bajar apenas termina con una pista (a menos que se encuentre en el tope). Sube
y baja únicamente si hay pedidos o no, por lo que se forman “mesetas”, que se generan
porque mientras no haya pedidos, el brazo no se mueve. Es por esto, se necesita un dato
adicional: la dirección del cabezal.
Este algoritmo no tiene inanición porque tarde o temprano se llega a todos los
pedidos.
Las desventajas de este algoritmo es que hay mucho tiempo perdido, como se lo
puede ver en el trayecto del 99 al 30. Por el otro lado, este tipo de algoritmos, y casi
todos los que vienen después, van a tener el mismo problema de inanición. Este
problema es que, si estoy en la pista 85 y empiezo a recibir pedidos constantemente en
dicha pista, entonces el brazo se quedara parado en la pista 85 durante mucho tiempo.
111
Lucila Canalini
C-SCAN: Scan circular. A diferencia del SCAN, es que cuando se llega al tope (sea arriba
o abajo), no se empieza a bajar, sino que el brazo cae casi en un tiempo de 0 ms (pasa
de 99 a 0 en un tiempo completamente despreciable. Por lo tanto, el brazo siempre va a
ascender (o descender, según sea el ejercicio).
Sufre la misma inanición que el SCAN. Si recibo infinitos pedidos de la pista 85,
nunca podré mover el cabezal de dicha pista.
LOOK: Casi igual al SCAN, con la diferencia que no llega hasta los topes. Si luego del
pedido de la pista 10, hubiese uno en la 50, no va a ir hasta la pista 0 para luego subir,
sino que va directamente.
También sufre inanición como los dos algoritmos previos.
C-LOOK: Hace lo mismo que el C-SCAN pero sin llegar a los topes. Cuando llega al 85 cae
hasta el 10, no hasta el 0. También sufre inanición.
Es el de menor tiempo siempre, pero hay algunas cuestiones de
implementaciones mecánicas de los discos que puede no permitir esta planificación.
112
Lucila Canalini
FSCAN: Utiliza dos colas de pedidos. La primera es la cola activa, van a estar los pedidos
que se está atendiendo en el momento. La segunda es la cola pasiva, están los pedidos
que voy a recibir mientras atiendo los de la lista activa. Los pedidos se van guardando y
hasta no terminar con una lista no sigo con la otra.
Se atienden los pedidos de la cola activa utilizando el algoritmo SCAN.
Lleva más tiempo que los anteriores, pero ya no hay más inanición, por el tema
de las dos listas de atención. Es una mezcla entre FIFO y SCAN.
N step SCAN: Utiliza colas de N pedidos o menos. Los pedidos se acumulan en varias
colas de tamaño N. Voy armando listas de tamaño N. Cada cola se atiende utilizando el
algoritmo SCAN. Es posible que las listas no queden completas, porque pasan de ser
pasivas a activas antes de que lleguen pedidos para completarlas y no pueden entrar si
ya es activa.
Es un algoritmo más justo que el anterior porque el orden de atención de las
colas es FIFO, y dentro de cada lista se utiliza el SCAN.
Si N = 2:
113
Lucila Canalini
Sea cual sea la planificación, si estaba en la pista 20 y estoy yendo a buscar la pista 25, pero
mientras lo hago, llega un pedido en la pista 23, no importa. Primero se debe terminar con el
pedido que se estaba atendiendo, luego se verá cuándo se atiende el pedido de la pista 23.
A menos que se diga lo contrario, el tamaño de un sector del disco es de 512 bytes. Si hago
Cant. de Sectores * 512 bytes = Capacidad Total del Disco
Cant. de Sectores = Cant. de Cilindros * Cant. de Cabezas * Cant. de Sectores por Pista
RAID (Redundant Array of Independent Disks)
Conjunto de discos que inicialmente se formaron porque el disco es muchísimo más lento que
el resto de dispositivos de E/S (más lento que la memoria, que el procesador, etc.). Para mejorar
la velocidad de atención de los pedidos, apareció RAID que son un conjunto de discos que tienen
cierta información. En todos los RAIDs los discos se dividen en bandas (stripes).
114
Lucila Canalini
En el RAID 0 lugar de tener toda la información en un solo disco, y lo que sobra en otro, por
ejemplo, la información se encuentra distribuida.
La ventaja es que en vez de atender cuatro pedidos de un disco, hago cuatro simultáneos en ¼
de tiempo. Por lo tanto, se ahorra mucho tiempo.
Con el paso del tiempo vieron que sería conveniente tener varios discos extras para tener más
seguridad. Los discos, al ser un dispositivo mecánico, tienen más chances de gastarse que los
dispositivos electrónicos. Por lo tanto, las posibilidades de una falla mecánica eran mayores.
El RAID 1 es el disco espejado. Tengo un disco con información, y tengo un segundo disco con
exactamente la misma información, los mismos archivos, idénticos, con la particularidad que
cada vez que hago una escritura tengo que escribir ambos. Agrega seguridad en cuanto que si
se me rompe el disco no pierdo información, sino que tengo que comprar otro disco, conectarlo,
y que se copie la información de nuevo.
El RAID 0+1 y el RAID 1+0, son una combinación del RAID 0 y el RAID 1, donde tengo
información distribuida en diferentes discos, y además tengo copia exacta de la información de
cada disco. Se vuelve muy costoso porque necesito un disco más por cada uno que tengo.
De esta forma, tenemos más velocidad al tener la información distribuida en diferentes discos,
y además tenemos más seguridad por tener las copias.
En el caso del RAID 1+0, si se me rompe un disco, lo reemplazo por uno vacío, y lo sincronizo
con la copia que tenía su copia de seguridad. Ni siquiera es necesario apagar la computadora
para hacer esto.
El RAID 2 es donde empiezo a mantener la seguridad, pero necesito menos discos. Por ejemplo,
para mantener la seguridad de 4 discos necesito 3. Para mantener la seguridad de 7 discos
necesito 4. Esto es muy específico por la forma que tiene de funcionar RAID 2, que utiliza algo
que se llama el código de haming. Gracias a este código tengo menos cantidad de discos para
recuperar las cosas.
115
Lucila Canalini
El RAID 6 es muy parecido al 5, pero en vez de agregar un disco de paridad, agrega dos. Esto es
porque en los RAIDs anteriores si se rompe un disco lo podemos recuperar, pero si se rompen
dos no. En este RAID si se puede.
El RAID 2, 3 y 4 ya casi no se usan. El RAID 0 se puede llegar a usar en algún ambiente que
necesita mucho rendimiento y velocidad. El RAID 1 se puede llegar a usar en un pequeño
servidor. Normalmente en empresas se utiliza RAID 5, RAID 6 o combinaciones, como lo es RAID
5+0.
Lo bueno de tener un RAID en el Sistema Operativo, es que podré tener más espacio, de forma
casera.
116