Otra opción para el manejo de la memoria es usar una forma de liberar al programador de la tarea del control de las tablas en expansión y contracción, de la misma forma que la memoria virtual elimina la preocupación por organizar el programa en una serie de proyectos.
Esto se puede lograr dotando a la máquina de varios espacios independientes de direcciones llamados segmentos. Cada segmento tiene una serie lineal de direcciones, desde 0 hasta cierto máximo. La longitud de cada segmento puede variar de 0 hasta un máximo permitido. Los distintos segmentos pueden tener y de hecho tienen por lo general, longitudes distintas. Además, la longitud de un segmento puede variar durante la ejecución. La longitud de un segmento de la pila puede crecer si algo entra a la pila y decrecer si algo sale de ella.
Puesto que cada segmento constituye un espacio independiente de direcciones, los distintos segmentos pueden crecer o reducirse en forma independiente sin afectar a los demás. En la figura 13 podemos ver una lista de comparación entre la paginación y la segmentación.
La segmentación también facilita el uso de procedimientos o datos compartidos entre varios procesos. Un ejemplo común son las bibliotecas compartidas (Shared DLL’s). Es frecuente que las estaciones de trabajo modernas que ejecutan sistemas avanzados, con ventanas, tengan bibliotecas gráficas de tamaño muy grande que se compilan casi en todos los programas. En un sistema segmentado, la biblioteca gráfica se puede colocar en un segmento y compartirse entre varios procesos, sin necesidad de tenerla en el espacio de direcciones de cada proceso.
Aunque también es posible tener bibliotecas compartidas sin los sistemas con paginación pura, es mucho más complejo. De hecho, estos sistemas simulan la segmentación.
Segmentación pura
La implantación de la segmentación difiere del caso de la paginación en un sentido esencial: las páginas tienen un tamaño fijo y los segmentos no. La figura 14 muestra un ejemplo de memoria física que contiene al principio 5 segmentos. Consideremos que el segmento 1 se elimina y su lugar se ocupa por el segmento 7, que es menor. El área que queda entre el segmento 7 y el 2 es un hueco. Luego, el segmento 4 se reemplaza por el segmento 5 y el segmento 3 es reemplazado por el segmento 6. Después de que el sistema esté en ejecución durante cierto tiempo, la memoria quedará dividida en varios bloques, algunos con segmentos y otros con huecos.
Considerando |
Paginación |
Segmentación |
¿Necesita saber el programador si está utilizando esta técnica? |
No |
Sí |
¿Cuántos espacios lineales de direcciones existen? |
1 |
Muchos |
¿Puede el espacio total de direcciones exceder el tamaño de la memoria física? |
Sí |
Sí |
¿Pueden distinguirse los procedimientos y los datos, además de protegerse en forma independiente? |
No |
Sí |
¿Pueden adecuarse con facilidad las tablas con tamaños fluctuantes? |
No |
Sí |
¿Se facilita el uso de procedimientos compartidos entre los usuarios? |
No |
Sí |
¿Para qué se inventó esta técnica? |
Para obtener un gran espacio lineal de direcciones sin tener que adquirir más memoria física |
Para permitir que los programas y datos fueran separados en espacios independientes de direcciones y poder proporcionar la protección y uso de objetos compartidos |
Fig. 13. Comparación de paginación y segmentación.
Este fenómeno de fragmentación externa o checkboarding, desperdicia la memoria correspondiente a los huecos, pero es fácilmente corregido mediante el uso de la compactación. De esta forma los huecos son unificados, generando así un hueco de tamaño suficiente para albergar algún otro segmento más.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Fig. 14. Desarrollo de fragmentación externa y su corrección mediante compactación.
Segmentación con paginación: MULTICS
En el sistema MULTICS, una dirección lógica está formada por un número de segmento de 18-bit y un offset de 16 bit. Aunque este esquema crea un espacio de dirección de 34-bit, la sobrecarga en la tabla de segmentos es tolerable; solo se requiere de las suficientes localidades en la tabla de segmentos como haya segmentos, puesto que no debe haber localidades vacías.
Sin embargo, con segmentos de palabras de 64K, es donde cada una consiste de 36 bits, el tamaño promedio de segmento puede ser grande y se podría presentar un problema de fragmentación externa. Aunque no lo fuera, el tiempo de búsqueda para ubicar un segmento, usando primer ajuste o mejor ajuste, puede ser prolongado. Lo que puede causar desperdicio de memoria debido a la fragmentación externa, o desperdicio de tiempo por las largas búsquedas o ambas.
La solución al problema es paginar los segmentos. La paginación elimina la fragmentación externa y convierte el problema de ubicación en algo trivial: cualquier frame desocupado puede ser usado para una página deseada. En MULTICS, cada página consiste de palabras de 1K. En consecuencia, el offset del segmento (16 bits) es dividido en un número de página de 6 bit y un offset de página de 10 bit. El número de página se indexa en la tabla de páginas para obtener el número de frame. Finalmente, el número de frame es combinado con el offset de página para formar una dirección física. El esquema de esto se muestra en la figura 15.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Fig. 15. Segmentación paginada en el GE 645 (MULTICS)
Ahora se debe de tener una tabla de páginas individual para cada segmento. Sin embargo, dado que cada segmento está limitado en tamaño por su ubicación en la tabla de segmentos, la tabla de páginas no tiene que ser de tamaño completo, solo requiere de los espacios que son realmente necesarios.
Al igual que en la paginación, la última página de cada segmento, por lo general no estará totalmente llena. En consecuencia, se tiene, en promedio, una fragmentación interna de media página por segmento.
Segmentación con paginación: Intel 386
El sistema operativo IBM OS/2 de 32 bits es un sistema operativo que corre con las arquitecturas del procesador Intel 386 y 486. El 386 una la segmentación con paginación para su manejo de memoria. El número máximo de segmentos por proceso es de 16K y cada segmento puede llegar a ser de hasta 4 gigabytes. El tamaño de página es de 4K.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Fig. 16. Traducción de dirección en el Intel 80386
El espacio de direcciones lógicas está dividido en dos particiones. La primera partición consiste en segmentos de hasta 8K los cuales son privados para ese proceso. La segunda partición también consiste en segmentos de hasta 8K, los cuales son compartidos entre todos los procesos. La información de la primera partición es guardada en la tabla descriptora local (LDT – Local Descriptor Table), y la de la segunda partición es guardada en la tabla descriptora global (GDT – Global Descriptor Table). Cada registro de las tablas LDT y GDT consiste de 8 bytes con información detallada sobre un segmento en particular incluyendo la ubicación base y longitud del segmento.
Cada segmento es paginado, y cada página es de 4K. Una tabla de páginas puede entonces consistir de hasta un millón de registros. Dado que cada registro consiste de 4 bytes, cada proceso puede llegar a necesitar hasta 4 megabytes de espacio de direcciones física para la tabla de páginas únicamente. Claro está que no sería conveniente alojar la tabla de páginas contigua en la memoria principal. La solución que es implementada en el esquema para el 386, es usar un esquema de paginación de dos niveles. La dirección lineal es dividida en un número de página consistente de 20 bits y un offset de página de 12 bits. Siendo que se pagina a la tabla de páginas, el número de páginas es a su vez dividido en un apuntador para el directorio de páginas de 10 bit y en un apuntador para la tabla de páginas de 10 bit. La transición de la dirección se puede apreciar en más detalle en la figura 16.
Capitulo 5
Comunicación y sincronización de procesos
Uno de los módulos más importantes de un sistema operativo es la de administrar los procesos y tareas del sistema de cómputo. En esta sección se revisarán dos temas que componen o conciernen a este módulo: la planificación del procesador y los problemas de concurrencia.
Planificación del procesador
La planificación del procesador se refiere a la manera o técnicas que se usan para decidir cuánto tiempo de ejecución y cuando se le asignan a cada proceso del sistema. Obviamente, si el sistema es monousuario y monotarea nohay mucho que decidir, pero en el resto de los sistemas esto es crucial para el buen funcionamiento del sistema.
Niveles de planificación
En los sistemas de planificación generalmente se identifican tres niveles: el alto, em medio y el bajo. El nivel alto decide que trabajos (conjunto de procesos) son candidatos a convertirse en procesos compitiendo por los recursos del sistema; el nivel intermedio decide que procesos se suspenden o reanudan para lograr ciertas metas de rendimiento mientras que el planificador de bajo nivel es el que decide que proceso, de los que ya están listos (y que en algún momento paso por los otros dos planificadores) es al que le toca ahora estar ejecutándose en la unidad central de procesamiento. En este trabajo se revisaran principalmente los planificadores de bajo nivel porque son los que finalmente eligen al proceso en ejecución.
Objetivos de la planificación
Una estrategia de planificación debe buscar que los procesos obtengan sus turnos de ejecución apropiadamente, conjuntamente con un buen rendimiento y minimización de la sobrecarga (overhead) del planificador mismo. En general, se buscan cinco objetivos principales:
Características a considerar de los procesos
Planificación apropiativa o no apropiativa (preemptive or not preemptive)
La planificación apropiativa es aquella en la cual, una vez que a un proceso le toca su turno de ejecución ya no puede ser suspendido, ya no se le puede arrebatar la unidad central de procesamiento. Este esquema puede ser peligroso, ya que si el proceso contiene accidental o deliberadamente ciclos infinitos, el resto de los procesos pueden quedar aplazados indefinidamente. Una planificación no apropiativa es aquella en que existe un reloj que lanza interrupciones periodicas en las cuales el planificador toma el control y se decide si el mismo proceso seguirá ejecutándose o se le da su turno a otro proceso. Este mismo reloj puede servir para lanzar procesos manejados por el reloj del sistema. Por ejemplo en los sistemas UNIX existen los 'cronjobs' y 'atjobs', los cuales se programan en base a la hora, minuto, día del mes, día de la semana y día del año.
En una planificación no apropiativa, un trabajo muy grande aplaza mucho a uno pequeño, y si entra un proceso de alta prioridad esté también debe esperar a que termine el proceso actual en ejecución.
Asignación del turno de ejecución
Los algoritmos de la capa baja para asignar el turno de ejecución se describen a continuación:
Proceso Espera desde Termina Tiempo de Espera
A 0 4 4
B 0 16 16
C 0 34 34
D 0 58 58
E 0 84 84
Tiempo promedio = (4 + 16 + 34 + 58 + 84 )/5 = 39 unidades.
tiempo que ha esperado + tiempo total para terminar
valor = ___________________________________________
tiempo total para terminar.
Es decir, que dinámicamente el valor se va modificando y mejora un poco las deficiciencias del algoritmo del trabajo más corto primero.
Problemas de Concurrencia
En los sistemas de tiempo compartido (aquellos con varios usuarios, procesos, tareas, trabajos que reparten el uso de CPU entre estos) se presentan muchos problemas debido a que los procesos compiten por los recursos del sistema. Imagine que un proceso está escribiendo en la unidad de cinta y se le termina su turno de ejecución e inmediatamente después el proceso elegido para ejecutarse comienza a escribir sobre la misma cinta. El resultado es una cinta cuyo contenido es un desastre de datos mezclados. Así como la cinta, existen una multitud de recursos cuyo acceso debe der controlado para evitar los problemas de la concurrencia.
El sistema operativo debe ofrecer mecanismos para sincronizar la ejecución de procesos: semáforos, envío de mensajes, 'pipes', etc. Los semáforos son rutinas de software (que en su nivel más interno se auxilian del hardware) para lograr exclusión mutua en el uso de recursos. Para entender este y otros mecanismos es importante entender los problemas generales de concurrencia, los cuales se describen enseguida.
Los problemas descritos son todos importantes para el sistema operativo, ya que debe ser capaz de prevenir o corregirlos. Tal vez el problema más serio que se puede presentar en un ambiente de concurrencia es el 'abrazo mortal', también llamado 'trabazón' y en inglés deadlock. El deadlock es una condición que ningún sistema o conjunto de procesos quisiera exhibir, ya que consiste en que se presentan al mismo tiempo cuatro condiciones necesarias: La condición de no apropiación, la condición de espera circular, la condición de exclusión mutua y la condición de ocupar y esperar un recurso. Ante esto, si el deadlock involucra a todos los procesos del sistema, el sistema ya no podrá hacer algo productivo. Si el deadlock involucra algunos procesos, éstos quedarán congelados para siempre.
En el área de la informática, el problema del deadlock ha provocado y producido una serie de estudios y técnicas muy útiles, ya que éste puede surgir en una sola máquina o como consecuencia de compartir recursos en una red.
En el área de las bases de datos y sistemas distribuidos han surgido técnicas como el 'two phase locking' y el 'two phase commit' que van más allá de este trabajo. Sin embargo, el interés principal sobre este problema se centra en generar técnicas para detectar, prevenir o corregir el deadlock.
Las técnicas para prevenir el deadlock consisten en proveer mecanismos para evitar que se presente una o varias de las cuatro condiciones necesarias del deadlock. Algunas de ellas son:
Para detectar un deadlock, se puede usar el mismo algoritmo del banquero, que aunque no dice que hay un deadlock, sí dice cuándo se está en estado inseguro que es la antesala del deadlock. Sin embargo, para detectar el deadlock se pueden usar las 'gráficas de recursos'. En ellas se pueden usar cuadrados para indicar procesos y círculos para los recursos, y flechas para indicar si un recurso ya está asignado a un proceso o si un proceso está esperando un recurso. El deadlock es detectado cuando se puede hacer un viaje de ida y vuelta desde un proceso o recurso. Por ejemplo, suponga los siguientes eventos:
evento 1: Proceso A pide recurso 1 y se le asigna.
evento 2: Proceso A termina su time slice.
evento 3: Proceso B pide recurso 2 y se le asigna.
evento 4: Proceso B termina su time slice.
evento 5: Proceso C pide recurso 3 y se le asigna.
evento 6: Proceso C pide recurso 1 y como lo está ocupando el proceso A, espera.
evento 7: Proceso B pide recurso 3 y se bloquea porque lo ocupa el proceso C.
evento 8: Proceso A pide recurso 2 y se bloquea porque lo ocupa el proceso B.
En la figura 5.1 se observa como el 'resource graph' fue evolucionando hasta que se presentó el deadlock, el cual significa que se puede viajar por las flechas desde un proceso o recurso hasta regresar al punto de partida. En el deadlock están involucrados los procesos A,B y C.
Una vez que un deadlock se detecta, es obvio que el sistema está en problemas y lo único que resta por hacer es una de dos cosas: tener algún mecanismo de suspensión o reanudación [Deitel93] que permita copiar todo el contexto de un proceso incluyendo valores de memoria y aspecto de los periféricos que esté usando para reanudarlo otro día, o simplemente eliminar un proceso o arrebatarle el recurso, causando para ese proceso la pérdida de datos y tiempo.
Capitulo 6
6.1. Los interbloqueos: Una historia basada en hechos reales.
El problema de los interbloqueos no se circunscribe únicamente al mundo de la informática, sino que aparece en muchos otros ámbitos incluyendo el de la vida cotidiana. De hecho, algunos de los ejemplos utilizados por los investigadores en este tema están inspirados en situaciones cotidianas.
El interbloqueo surge debido a que se produce un conflicto entre las necesidades de los dos vehículos: el recurso que necesita cada vehículo lo posee el otro. Hay que resaltar que otros vehículos que intentarán cruzar el puente en ese momento en cualquiera de los dos sentidos se quedarían detenidos detrás de ellos viéndose, por tanto, implicados también en el interbloqueo.
Las posibles estrategias para tratar el problema de los interbloqueos son:
Una vez detectada la situación de interbloqueo uno de los vehículos debe liberar el recurso que posee para dejar que el otro lo utilice. Una posible recuperación de esta situación consistiría en seleccionar uno de los sentidos de circulación y hacer que el vehículo o vehículos detenidos en ese sentido dieran marcha atrás hasta el principio del puente, liberando así el paso en el otro sentido (se está suponiendo que un vehículo tiene capacidad para avanzar marcha atrás, sino fuera así, habría que tomar una acción más drástica como tirarlo al río que pasa por debajo del puente). Debería existir una política para determinar qué vehículo debe retroceder.
Un punto importante a resaltar en este ejemplo y, en general, sobre los interbloqueos es que, antes de producirse el interbloqueo propiamente dicho (los vehículos detenidos frente a frente), existe un <<punto de retorno>> a partir del cual el interbloqueo es inevitable.
Capitulo 7
El código destinado a manejar la entrada y salida de los diferentes periféricos en un sistema operativo es de una extensión considerable y sumamente complejo. Resuelve las necesidades de sincronizar, atrapar interrupciones y ofrecer llamadas al sistema para los programadores. En esta sección se repasarán los principios más importantes a tomar en cuenta en este módulo del sistema operativo.
Dispositivos de Entrada - Salida
Los dispositivos de entrada salida se dividen, en general, en dos tipos: dispositivos orientados a bloques y dispositivos orientados a caracteres. Los dispositivos orientados a bloques tienen la propiedad de que se pueden direccionar, esto es, el programador puede escribir o leer cualquier bloque del dispositivo realizando primero una operación de posicionamiento sobre el dispositivo. Los dispositivos más comunes orientados a bloques son los discos duros, la memoria, discos compactos y, posiblemente, unidades de cinta. Por otro lado, los dispositivos orientados a caracteres son aquellos que trabajan con secuencias de byes sin importar su longitud ni ningúna agrupación en especial. No son dispositivos direccionables. Ejemplos de estos dispositivos son el teclado, la pantalla o display y las impresoras.
La clasificación anterior no es perfecta, porque existen varios dispositivos que generan entrada o salida que no pueden englobarse en esas categorías. Por ejemplo, un reloj que genera pulsos. Sin embargo, aunque existan algunos periféricos que no se puedan categorizar, todos están administrados por el sistema operativo por medio de una parte electrónica - mecánica y una parte de software. [Tan92].
Controladores de Dispositivos (Terminales y Discos Duros)
Los controladores de dispositivos (también llamados adaptadores de dispositivos) son la parte electrónica de los periféricos, el cual puede tener la forma de una tarjeta o un circuito impreso integrado a la tarjeta maestra de la computadora. Por ejemplo, existen controladores de discos que se venden por separado y que se insertan en una ranura de la computadora, o existen fabricantes de computadoras que integran esa funcionalidad en la misma tarjeta en que viene la unidad central de procesamiento (tarjeta maestra).
Los controladores de dispositivos generalmente trabajan con voltajes de 5 y 12 volts con el dispositivo propiamente, y con la computadora a través de interrupciones. Estas interrupciones viajan por el 'bus' de la computadora y son recibidos por el CPU el cual a su vez pondrá en ejecución algún programa que sabrá qué hacer con esa señal. A ese programa se le llama 'manejador de disposito' (device driver). Algunas veces el mismo controlador contiene un pequeño programa en una memoria de solo lectura o en memoria de acceso aleatoria no volátil y re-escribible que interactúa con el correspondiente manejador en la computadora. En la figura 6.1 se muestra un esquema simple de dispositivos orientados a bloques y otros a caracteres.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Por ejemplo, la terminal (CRT) tiene un 'chip' que se encarga de enviar cadenas de bits por medio de un cable serial que a su vez son recibidos por un controlador de puerto serial en la computadora. Este 'chip' también se encarga de leer secuencias de bits que agrupa para su despiegue en la pantalla o para ejecutar algunas funciones de control. Lo importante en todos estos dispositivos es que se debe ejercer un mecanismo para sincronizar el envío y llegada de datos de manera concurrente.
Para intercambiar datos o señales entre la computadora y los controladores, muchas veces se usan registros o secciones predefinidas de la memoria de la computadora. A este esquema se le llama 'manejo de entrada - salida mapeado por memoria' (memory mapped I/O). Por ejmplo, para una IBM PC se muestran los vectores de interrupción y las direcciones para la entrada -salida en la tabla 6.1.
Controlador Dirección(Hex) Vector de Interrupción
Reloj 040 - 043 8
Teclado 060 - 063 9
Disco Duro 320 - 32F 13
Impresora 378 - 37F 15
Monitor Mono 380 - 3BF -
Monitor Color 3D0 - 3DF -
Disco Flexible 3F0 - 3F7 14
Acceso Directo a Memoria (DMA)
El acceso directo a memoria se inventó con el propósito de liberar al CPU de la carga de atender a algunos controladores de dispositivos. Para comprender su funcionamiento vale la pena revisar cómo trabaja un controlador sin DMA. Cuando un proceso requiere algunos bloques de un dispositivo, se envia una señal al controlador con la dirección del bloque deseado. El controlador lo recibe a través del 'bus' y el proceso puede estar esperando la respuesta (trabajo síncrono) o puede estar haciendo otra cosa (trabajo asíncrono). El controlador recibe la señal y lee la dirección del bus. Envía a su vez una o varias señales al dispositivo mecánico (si es que lo hay) y espera los datos. Cuando los recibe los escribe en un buffer local y envía una señal al CPU indicándole que los datos están listos. El CPU recibe esta interrupción y comienza a leer byte por byte o palabra por palabra los datos del buffer del controlador (a través del device driver) hasta terminar la operación.
Como se ve, el CPU gasta varios ciclos en leer los datos deseados. El DMA soluciona ese problema de la manera siguiente. Cuando un proceso requiere uno o varios bloques de datos, el CPU envía al controlador la petición junto con el número de bytes deseados y la dirección de en dónde quiere que se almacenen de regreso. El DMA actuará como un 'cpu secundario' [Stal92] en cuanto a que tiene el poder de tomar el control del 'bus' e indicarle al verdadero CPU que espere. Cuando el controlador tiene listos los datos, el DMA 'escucha' si el 'bus' está libre aprovechando esos ciclos para ir leyendo los datos del buffer del controlador e ir escribiéndolos en el área de memoria que el CPU le indicó. Cuando todos los datos fueron escritos, se le envía una interrupción al CPU para que use los datos. El ahorro con el DMA es que el CPU ya no es interrumpido (aunque sí puede ser retardado por el DMA) salvando así el 'cambio de contexto' y además el DMA aprovechará aquellos ciclos en que el 'bus' no fue usado por el CPU.
El hecho de que los controladores necesiten buffers internos se debe a que conforme ellos reciban datos de los dispositivos que controlan, los deben poder almacenar temporalmente, ya que el CPU no está listo en todo momento para leerlos.
Principios en el Software de Entrada - Salida
Los principios de software en la entrada - salida se resumen en cuatro puntos: el software debe ofrecer manejadores de interrupciones, manejadores de dispositivos, software que sea independiente de los dispositivos y software para usuarios.
El primer objetivo referente a los manejadores de interrupciones consiste en que el programador o el usuario no debe darse cuenta de los manejos de bajo nivel para los casos en que el dispositivo está ocupado y se debe suspender el proceso o sincronizar algunas tareas. Desde el punto de vista del proceso o usuario, el sistema simplemente se tardó más o menos en responder a su petición.
El sistema debe proveer los manejadores de dispositivos necesarios para los periféricos, así como ocultar las peculiaridades del manejo interno de cada uno de ellos, tales como el formato de la información, los medios mecánicos, los niveles de voltaje y otros. Por ejemplo, si el sistema tiene varios tipos diferentes de discos duros, para el usuario o programador las diferencias técnicas entre ellos no le deben importar, y los manejadores le deben ofrecer el mismo conjunto de rutinas para leer y escribir datos.
Software independiente del dispositivo
Este es un nivel superior de independencia que el ofrecido por los manejadores de dispositivos. Aquí el sistema operativo debe ser capaz, en lo más posible, de ofrecer un conjunto de utilerías para accesar periféricos o programarlos de una manera consistente. Por ejemplo, que para todos los dispositivos orientados a bloques se tenga una llamada para decidir si se desea usar 'buffers' o no, o para posicionarse en ellos.
La mayoría de las rutinas de entrada - salida trabajan en modo privilegiado, o son llamadas al sistema que se ligan a los programas del usuario formando parte de sus aplicaciones y que no le dejan ninguna flexibilidad al usuario en cuanto a la apariencia de los datos. Existen otras librerías en donde el usuario si tiene poder de decisión (por ejemplo la llamada a "printf" en el lenguaje "C"). Otra facilidad ofrecida son las áreas de trabajos encolados (spooling areas), tales como las de impresión y correo electrónico.
Los relojes son esenciales para el buen funcionamiento de cualquier sistema porque juegan un papel decisivo en la sincronización de procesos, en la calendarización de trabajos por lote y para la asignación de turnos de ejecución entre otras tareas relevantes. Generalmente se cuenta con dos relojes en el sistema: uno que lleva la hora y fecha del sistema y que oscila entre 50 y 60 veces por segundo y el reloj que oscila entre 5 y 100 millones de veces por segundo y que se encarga de enviar interrupciones al CPU de manera periódica. El reloj de mayor frecuencia sirve para controlar el tiempo de ejecución de los procesos, para despertar los procesos que están 'durmiendo' y para lanzar o iniciar procesos que fueron calendarizados.
Para mantener la hora y fecha del sistema generalmente se usa un registro alimentado por una pila de alta duración que almacena estos datos y que se programan de fábrica por primera vez. Así, aunque se suspenda la energía la fecha permanece. Para lanzar procesos (chequeo de tiempo ocioso de un dispositivo, terminación del time slice de un proceso, etc), se almacena un valor en un registro (valor QUANTUM) el cual se decrementa con cada ciclo del reloj, y cuando llega a cero se dispara un proceso que ejecutará las operaciones necesarias (escoger un nuevo proceso en ejecución, verificar el funcionamiento del motor del disco flexible, hacer eco de un caracter del teclado, etc).
Capitulo 8
Gestión de Archivos y Directorios
Un sistema de archivos ( file system ) es una estructura de directorios con algún tipo de organización el cual nos permite almacenar, crear y borrar archivos en diferentes formatos. En esta sección se revisarán conceptos importantes relacionados a los sistemas de archivos.
Almacenamiento Físico de Datos
En un sistema de cómputo es evidente que existe la necesidad por parte de los usuarios y aplicaciones de almacenar datos en algún medio, a veces por periodos largos y a veces por instantes. cada aplicación y cada usuario debe tener ciertos derechos con sus datos, como son el poder crearlos y borrarlos, o cambialos de lugar; así como tener privacidad contra otros usuarios o aplicaciones. El subsistema de archivos del sistema operativo se debe encargar de estos detalles, además de establecer el formato físico en el cual almacenará los datos en discos duros, cintas o discos flexibles. Debe ser conocido por todos que tradicionalmente la información en los sistemas modernos se almacena en discos duros, flexibles y unidades de disco óptico, y en todos ellos se comparten algunos esquemas básicos para darles formato físico: las superficies de almacenamiento son divididas en círculos concéntricos llamados "pistas" y cada pista se divide en "sectores". A la unión lógica de varias pistas a través de varias superficies "paralelas" de almacenamiento se les llama "cilindros", los cuales son inspeccionados al momento de lectura o escritura de datos por las respectivas unidades fisicas llamadas "cabezas". Las superficies de almacenamiento reciben el nombre de "platos" y generalmente están en movimiento rotatorio para que las cabezas accesen a las pistas que los componen. Los datos se escriben a través de los sectores en las pistas y cilindros modificando las superficies por medio de las cabezas.
El tiempo que una cabeza se tarda en ir de una pista a otra se le llama "tiempo de búsqueda" y dependerá de la distancia entre la posición actual y la distancia a la pista buscada. El tiempo que tarda una cabeza en ir del sector actual al sector deseado se le llama tiempo de latencia y depende de la distancia entre sectores y la velocidad de rotación del disco. El impacto que tiene las lecturas y escrituras sobre el sistema está determinado por la tecnología usada en los platos y cabezas y por la forma de resolver las peticiones de lectura y escritura, es decir, los algoritmos de planificación.
Algoritmos de planificación de peticiones
Los algoritmos de planificación de peticiones de lectura y escritura a discos se encargan de registrar dichas peticiones y de responderlas en un tiempo razonable. Los algoritmos más comunes para esta tarea son:
Asignación del espacio de almacenamiento
El subsistema de archivos se debe encargar de localizar espacio libre en los medios de almacenamiento para guardar archivos y para después borrarlos, renombrarlos o agrandarlos. Para ello se vale de localidades especiales que contienen la lista de archivos creados y por cada archivo una serie de direcciones que contienen los datos de los mismos. Esas localidades especiales se llaman directorios. Para asignarle espacio a los archivos existen tres criterios generales que se describen enseguida.
Métodos de acceso en los sistemas de archivos
Los métodos de acceso se refiere a las capacidades que el subsistema de archivos provee para accesar datos dentro de los directorios y medios de almacenamiento en general. Se ubican tres formas generales: acceso secuencial, acceso directo y acceso directo indexado.
Operaciones soportadas por el subsistema de archivos
Independientemente de los algoritmos de asignación de espacio, de los métodos de acceso y de la forma de resolver las peticiones de lectura y escritura, el subsistema de archivos debe proveer un conjunto de llamadas al sistema para operar con los datos y de proveer mecanismos de protección y seguridad. Las operaciones básicas que la mayoría de los sistemas de archivos soportan son:
Algunas facilidades extras de los sistemas de archivos
Algunos sistemas de archivos proveen herramientas al administrador del sistema para facilitarle la vida. Las más notables es la facilidad de compartir archivos y los sistemas de `cotas'.
La facilidad de compartir archivos se refiere a la posibilidad de que los permisos de los archivos o directorios dejen que un grupo de usuarios puedan accesarlos para diferentes operaciones" leer, escribir, borrar, crear, etc. El dueño verdadero es quien decide qué permisos se aplicarán al grupo e, incluso, a otros usuarios que no formen parte de su grupo. La facilidad de `cotas' se refiere a que el sistema de archivos es capaz de llevar un control para que cada usuario pueda usar un máximo de espacio en disco duro. Cuando el usuario excede ese límite, el sistema le envía un mensaje y le niega el permiso de seguir escribiendo, obligándolo a borrar algunos archivos si es que quiere almacenar otros o que crezcan. La versión de UNIX SunOS contiene esa facilidad.
Los sistemas de archivos aislados son aquellos que residen en una sola computadora y no existe la posibilidad de que, aún estando en una red, otros sistemas puedan usar sus directorios y archivos. Por ejemplo, los archivos en discos duros en el sistema MS-DOS clásico se puede ver en esta categoría.
Sistemas de Archivos Compartidos o de Red
Estos sistemas de archivos es factible accesarlos y usarlos desde otros nodos en una red. Generalmente existe un `servidor' que es la computadora en donde reside el sistema de archivos físicamente, y por otro lado están los `clientes', que se valen del servidor para ver sus archivos y directorios de manera como si estuvieran localmente en el cliente. Algunos autores les llaman a estos sistemas de archivos `sistemas de archivos distribuídos' lo cual no se va a discutir en este trabajo.
Los sistemas de archivos compartidos en red más populares son los provistos por Netware, el Remote Filke Sharing ( RFS en UNIX ), Network File System ( NFS de Sun Microsystems ) y el Andrew File System ( AFS ). En general, lo que proveen los servidores es un medio de que los clientes, localmente, realicen peticiones de operaciones sobre archivos los cuales con `atrapadas' por un `driver' o un `módulo' en el núcleo del sistema operativo, el cual se comunica con el servidor a través de la red y la operación se ejecuta en el servidor. Existen servidores de tipo "stateless y no-stateless". Un servidor "stateless" no registra el estado de las operaciones sobre los archivos, de manera que el cliente se encarga de todo ese trabajo. La ventaja de este esquema es que si el servidor falla, el cliente no perderá información ya que ésta se guarda en memoria localmente, de manera que cuando el servidor reanude su servicio el cliente proseguirá como si nada hubiese sucedido. Con un servidor "no-stateless", esto no es posible.
La protección sobre las operaciones se lleva a cabo tanto el los clientes como en el servidor: si el usuario quiere ejecutar una operación indebida sobre un archivo, recibirá un mensaje de error y posiblemente se envíe un registro al subsistema de `seguridad' para informar al administrador del sistema de dicho intento de violación.
En la práctica, el conjunto de permisos que cada usuario tiene sobre el total de archivos se almacena en estructuras llamadas `listas de acceso' ( access lists ).
Con el gran auge de las redes de comunicaciones y su incremento en el ancho de banda, la proliferación de paquetes que ofrecen la compartición de archivos es común. Los esquemas más solicitados en la industria es el poder accesar los grandes volúmenes de información que residen en grandes servidores desde las computadoras personales y desde otros servidores también. Es una realidad que la solución más socorrida en las empresas pequeñas es usar Novell Netware en un servidor 486 o superior y accesar los archivos desde máquinas similares.
A veces se requieren soluciones más complejas con ambientes heterogéneos:
diferentes sistemas operativos y diferentes arquitecturas. Uno de los sistemas de archivos más expandidos en estaciones de trabajo es el NFS, y prácticamente todas las versiones de UNIX traen instalado un cliente y hasta un servidor de este servicio. Es posible así que una gran cantidad de computadoras personales (de 10 a 80 ) accesen grandes volúmenes de información o paquetería (desde 1 a 8 Gygabytes ) desde una sola estación de trabajo, e incluso tener la flexibilidad de usar al mismo tiempo servidores de Novell y NFS. Soluciones similares se dan con algunos otros paquetes comerciales, pero basta ya de `goles'. Lo importante aquí es observar que el mundo se va moviendo poco a poco hacia soluciones distribuídas, y hacia la estandarización que, muchas veces, es `de facto'.
Capitulo 11.
Estudio de casos: linux.
El origen de LINUX esta en MINIX que es un Sistema Operativo de carácter pedagógico basado en un microkernel. Fue desarrollado por Andrew S. Tanenbaum. Con el objetivo principal de que sirviera de apoyo para la enseñanza de sistemas operativos.
Andrew, intentaba demostrar al crear MINIX que se podía construir un sistema operativo mas sencillo y fiable pero a la vez muy eficiente.
MINIX presentaba las siguientes características:
En 1990 un estudiante Finlandés llamado LINUS TORVALDS, con ganas de ampliar sus conocimientos envío un mensaje a un grupo de noticias comp.os.minix, comentando que estaba desarrollando un nuevo sistema operativo tomando como base MINIX. Se estaba produciendo el humilde nacimiento de LINUX, cuya primera versión(numerada como 0.01) vio la luz a mediados del año de 1991.
LINUX tomaba prestadas numerosas características de MINIX por ejemplo el sistema de archivos. De hecho LINUX se desarrollo usando como plataforma de trabajo MINIX y las primeras versiones de LINUX no eran autónomas sino que tenían que arrancarse desde MINIX.
MINIX y LINUX son radicalmente diferentes. Por un lado LINUX solventa muchas de las deficiencias de MINIX como la carencia de memoria virtual. Estas mejoras permiten que se trate de un sistema adecuado para trabajar de memoria profesional, no limitándose su uso a un entorno académico , pero la diferencia la diferencia mas importante entre ellos esta en su organización interna. Mientras que MINIX tiene una estructura moderna basada en un Microkernel, LINUX posee una estructura monolítica mas clásica. Desde su lanzamiento publico en 1991, LINUX ha ido evolucionando e incorporando nuevas características. Además se transportado a otros procesadores como SPARC, ALPHA Y MIPS. En la actualidad es un sistema con unas características y prestaciones comparables a las de cualquier sistema operativo comercial.
11.2 Características y estructura de LINUX.-
LINUX es un sistema de tipo UNIX y, por tanto, posee las características típicas de los sistemas UNIX, LINUX se trata de un sistema multiusuarios y multitarea de propósito general.
Características especificas de LINUX.
En cuanto a la estructura de LINUX, como se comentó previamente, tiene una organización monolítica al igual que ocurre con la mayoría de las implementaciones de UNÍS. A pesar de este carácter monolítico, el núcleo no es algo estático y cerrado sino que se pueden añadir y quitar módulos de código en tiempo de ejecución. Se trata de un mecanismo similar al de las bibliotecas dinámicas pero aplicado al propio sistema operativo. Se pueden añadir módulos que correspondan con nuevos tipos de sistemas de archivos, nuevos manejadores de dispositivos o gestores de nuevos formatos de ejecutables.
Un sistema LINUX completo no sólo está formado por el núcleo monolítico sino también incluye programas del sistema (como, por ejemplo, demonios) y bibliotecas del sistema.
Debido a las dificultades que hay para instalar y configurar el sistema, existen diversas distribuciones de LINUX que incluyen el núcleo, los programas y bibliotecas del sistema, así como un conjunto de herramientas de instalación y configuración que facilitan considerablemente esta ardua labor. Hay distribuciones tanto de carácter comercial como gratuitas. Algunas de las distribuciones más populares son Slackware, Debian, suse y Red Hat.
11.3 gestión de procesos.
La gestión de procesos en LINUX es básicamente igual en cualquier otra variedad de UNÍS. Un aspecto original de LINUX es el servicio clone que es una extensión del clásico fork.
Este nuevo servicio permite crear un proceso que comparta con el padre su mapa de memoria, sus rutinas de manejo de señales y sus descriptores de archivos. Aunque LINUX no implementa threads en el núcleo, se pueden construir bibliotecas de threads usando este nuevo servicio.
En cuanto a la sincronización dentro del núcleo, siguiendo la tradición de UNÍS, LINUX no permite que haya llamadas concurrentes activas dentro del sistema operativo. Así se produce un evento que causa un cambio de proceso mientras se está ejecutando una llamada al sistema (por ejemplo, una interrupción de reloj), el cambio se difiere hasta que la llamada termina o se bloquea. Para evitar las condiciones de carrera entre la ejecución de una llamada y el tratamiento de una interrupción, se prohíben las interrupciones en pequeñas zonas del código del sistema.
Puesto que el código del rutina de interrupción ejecuta con una prioridad lata bloqueando el tratamiento de las interrupciones, es importante que estas rutinas sean muy cortas. Para ayudar a lograr este objetivo, LINUX ofrece un mecanismo que permite dividir las operaciones asociadas a una interrupción en dos partes:
En cuanto a la planificación, LINUX soporta tres clases de planificación: un algoritmo de tiempo compartido y dos algoritmos de planificación de tiempo real que se corresponden con los definitivos por POSIX.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Figura 11.1
El servicio sched_setscheduler permite definir la clase de planificación del proceso que la invoca. Esta llamada sólo puede hacerla un proceso privilegiado. Cada de tiempo real tiene asociada una prioridad y un tipo de planificación que puede ser FIFO o Round-Robin. El planificador selecciona en cada momento el proceso listo para ejecutar que tenga mayor prioridad. Si el proceso de este tipo FIFO, seguirá ejecutando hasta que bloquee. Si es de tipo Round-Robin, cuando termine su rodaja, el proceso pasará al final de la cola de procesos listos para ejecutar de su misma prioridad.
Todo proceso tiene asociada una prioridad base. Inicialmente la prioridad del proceso es igual a su prioridad base. Cada vez que se produce una interrupción de reloj se resta una unidad a la prioridad del proceso que estaba ejecutando. El algoritmo de planificación está basado en la prioridad del proceso y tiene carácter exclusivo: el planificador elige el proceso listo para ejecutar que tenga mayor prioridad.
LINUX tiene un sistema de memoria que incluye todas las características habituales en los sistemas modernos. Estas características ya fueron discutidas en el capítulo dedicado a este tema, por lo que en esta sección se presentan aquellos aspectos específicos de LINUX:
11.5 entrada/salida.
La entrada/salida en LINUX es muy similar a la de cualquier otro sistema UNIX. Se distinguen, por tanto, 2 tipos de dispositivos: dispositivos de bloques y dispositivos de caracteres.
Como el resto de sistemas UNIX, se utiliza una caché común
Para todos los dispositivos de bloques. El tamaño de la caché es dinámico y crece de acuerdo a las necesidades de memoria del resto de sistema. Para gestionarla se usa básicamente una política de reemplazo LRU. En las últimas versiones esta caché trabaja coordinadamente con la utilizada por el gestor de memoria.
En cuanto al acceso a los discos, se utiliza el algoritmo del ascensor con un único sentido d servicio.
Siguiendo el modelo de UNIX, en LINUX los usuarios ven los dispositivos como archivos y utilizan los servicios destinados a trabajar con archivos para acceder a los dispositivos.
La red, sin embargo, es un dispositivo que tiene un tratamiento un poco diferente. El usuario no puede acceder a este dispositivo de la misma manera que a un archivo. La parte del sistema operativo que trata la red está dividida en tres niveles:
11.6. Sistema de archivos.
LINUX da soporte a una gran variedad de tipos de sistemas de archivos en los que se incluyen los distintos sistemas de archivos de windows y de otros sistemas UNIX. Además, cualquier usuario puede programar un manejador de un nuevo tipo de sistema de archivos e incluirlo en el sistema como un módulo.
Esta coexistencia de distintos tipos de sistemas de archivos la posibilita el VFS (virtual file system, sistema virtual de archivos).
Aunque admite muy diferentes tipos de sistemas de archivos, LINUX tiene sus propio sistema de archivos que se denomina ext2fs. Este sistema evolucionó desde el sistema de archivos de MINIX. Se le fueron añadiendo nuevas características al sistema de archivos de MINIX hasta llegar al sistema extfs. Posteriormente se rediseñó dando lugar al ext2fs actual. Se trata de un sistema basado en el FFS (fast file system, sistema de archivos rápidos) del UNIX BSD.
Merece mención aparte un tipo de sistema de archivos muy especial: el sistema de archivos proc. Este sistema de archivos no tiene soporte en ningún dispositivo. Su objetivo es poner a disposición del usuario datos del estado del sistema en la forma d archivos. Esta idea no es original de LINUX ya que casi todos los sistemas UNIX la incluyen. Sin embargo, LINUX se caracteriza por ofrecer más información del sistema que el resto de variedades de UNIX. En este sistema de archivos se puede acceder a información general sobre características y estadísticas del sistema, así como información sobre los distintos procesos existentes.
Para ver el gráfico seleccione la opción "Descargar" del menú superior
Figura 11.2. Niveles del sistema de archivos.
Capitulo 12.
Estudio de casos: Windows NT.
12.1. Introducción.
Windows NT es un sistema operativo multitarea, basado en 32 bits, cuyas características principales son su diseño orientado a objetos, el subsistema de seguridad y los servicios de entrada y salida.
La historia de este sistema operativo empezó en 1989, cuando Microsoft decidió diseñar un nuevo sistema que sustituyera a Windows 3.x y que incluyera las características adecuadas para ser usadas en máquinas multiprocesos de grandes dimensiones, para lo que versiones anteriores de Windows no eran válidas. Para ello contrató a expertos en diseño de sistemas operativos, como Dave Cutler de DEC, que aportaron al diseño de Windows NT muchas de las ideas existentes en otros sistemas operativos.
12.2. Principio de diseño de Windows NT.
Windows NT tiene un diseño moderno de tipo micro núcleo, con una pequeña capa de núcleo que da soporte a las restantes funciones del ejecutivo del sistema operativo. Dentro del ejecutivo destaca la integración del modelo de seguridad (nivel C2), de la gestión de red, de la existencia de sistemas d archivos robustos y de aplicación exhaustiva del modelo orientado a objetos.
Los principios de diseño fundamentales se parecen mucho a los de otros sistemas operativos:
12.3. Arquitectura de Windows NT.
Windows NT tiene una por capas muy modular, en la que cada capa está compuesta de varios módulos relativamente simples y con una funcionalidad muy específica.
El sistema operativo está compuesta por las siguientes capas:
12.4. El núcleo de Windows NT.
El núcleo es la base de Windows NT ya que planifica las actividades, denominadas threads, de los procesadores de la computadora. Al igual que en UNIX, el núcleo de Windows NT se ejecuta siempre en modo seguro (modo núcleo) y no usa la memoria virtual (no paginable). El software del núcleo no se puede expulsar de la UCP y, por tanto, no hay cambios de contexto durante su ejecución. En caso en que se ejecute en un multiprocesador se puede ejecutar simultáneamente en todos los procesadores.
El núcleo proporciona las siguientes funciones al resto del sistema:
El modelo de objetos está en la base de funcionamiento del núcleo, que proporciona dos tipos de de objetos básicos:
Un objeto contiene un nombre, un manejador, un descriptor de seguridad, una lista de manejadores de objetos abiertos, una descripción del tipo de objeto que almacena y un cuerpo que incluye información específica del objeto.
Para almacenar la información acerca de los objetos y sus atributos, el núcleo gestiona las siguientes estructuras de datos:
Además de estas estructuras se mantienen otras como las colas de dispositivos, las petición de procesadores y recursos, etc.
12.5 el ejecutivo de Windows NT.
La capa mas compleja del sistema operativo es el ejecutivo, un conjunto de servicios comunes que pueden ser usados por todos los subsistemas de entorno de ejecución existentes en Windows NT a través de la capa de servicios del sistema.
Cada grupo de servicios es manejado por uno de los siguientes componentes:
12.5. Gestor de objetos.
El gestor de objetos es el componente del ejecutivo de Windows NT que se encarga de proporcionar servicios para todos los aspectos de los objetos, incluyendo reglas para nombres y seguridad. Todo el funcionamiento del sistema operativo se basa en los objetos, que son instancias en tiempo de ejecución de un tipo objeto particular que pueden ser manipuladas por algún componente del sistema operativo. Un tipo objeto está compuesto por un tipo de datos estructurado definido por el sistema y las operaciones que se pueden hacer sobre este tipo de datos y conjunto de atributos de datos para dichas operaciones.
Línea del Tiempo de Linux
El padre de Linux es Linus Torvalds, un programador finlandés de 21 años que inicialmente no tenía más pretensión que 'divertirse' creando un sistema operativo para su uso personal. Torvalds
colocó Linux en Internet para que cualquiera lo bajara gratis, en 1991, y desde entonces participan en su desarrollo cientos de voluntarios. Hoy Linux se difunde más rápido que cualquier otro sistema operativo, es venerado por una comunidad de diez millones de usuarios y comienza a verse como una alternativa real a Windows. Esta es su historia.
1991
- En abril, Linus Torvalds comenzó a crear un programa que varios meses después se convertiría en Linux, un sistema operativo Unix para PC (Unix es un sistema operativo usado en estaciones de trabajo y otros computadores de alto rend