1. Estructura del sistema



Figura 2. Bloques funcionales del sistema operativo UNIX.






Sistema de Archivos (File System)

2.1 Organización de la información:

Figura 3. Estructura del sistema de archivos.

          Aunque en un principio pueda parecer una estructura excesivamente complicada por la amplia ramificación de los directorios, esta organización permite agrupar los archivos de los diferentes usuarios e incluso de las diferentes aplicaciones en directorios separados, con lo que se evita el que se interfieran entre sí. Por otro lado, un mismo usuario puede organizar su propia información separando los archivos en diferentes directorios de acuerdo a su contenido.


2.2 Concepto de archivo:

          La estructura fundamental que utiliza el UNIX para almacenar información es el archivo. El UNIX mantiene la pista de cada uno de los archivos asignándole a cada uno, un número de identificación (i-number) que apunta a la tabla de i-nodos. El usuario, no obstante, indicará cada archivo por medio de su nombre asignado por el propio usuario. El UNIX mantiene toda la información propia del archivo, excepto su nombre, en su inodo correspondiente. El nombre se encuentra en la entrada correspondiente del directorio al que pertenece.

          Todos los archivos UNIX son tratados como una simple secuencia de bytes (caracteres), comenzando en el primer byte del archivo y terminando con el último. Un byte en concreto dentro del archivo, es identificado por la posición relativa que ocupe en el archivo. La organización de los archivos en registros o bloques de una longitud fija, corresponde a la forma tradicional de organización de los datos en el disco. El UNIX protege específicamente al usuario del concepto de registros o bloques. En su lugar, el UNIX puede permitir que el usuario divida al archivo en registros, de acuerdo a un byte o conjunto de bytes especiales. Los programas son libres para organizar sus archivos, con independencia de la forma en que los datos estén almacenados en el disco.



2.3 Directorios:

          Prácticamente para todos los efectos, un directorio se comporta como un archivo, con la característica de que sus registros son de longitud fija. A pesar de lo comentado anteriormente, el contenido de los directorios no apunta directamente a los bloques de datos de los archivos o subdirectorios que dependen de él, sino a unas tablas (i-nodos) separadas de la estructura. Es desde estas tablas desde las que se apunta a los bloques físicos de los archivos dentro del disco.

          Cada registro en el directorio tiene una longitud de 16 bytes de los que:

    • Los dos primeros contienen un apuntador (en binario) a la tabla de los i-nodos (i-number).
    • Los catorce restantes contienen el nombre del archivo o subdirectorio (el número bytes por registro depende de la versión del UNIX, ya que hay versiones en que la longitud del nombre de un archivo puede llegar a 255 bytes).

          Cualquier directorio contiene un mínimo de dos entradas:

    • Una referencia a sí mismo (.).
    • Una referencia al directorio de que dependo o directorio padre (..), salvo en el directorio raíz que, al ser el comienzo de la estructura, esta referencia es también sobre sí mismo.

Figura 4. Estructura de un directorio.

aaa
2.4 Sistema de archivos:

          El conjunto formado por la estructura de archivos y directorios y las tablas de inodos, se denomina Sistema de Archivos o File System. Cada sistema de archivos está residente en un soporte físico, normalmente disco magnético, pero si el disco es de gran capacidad puede dividirse en varios discos lógicos o "particiones", cada uno de los cuales sería un sistema de archivos independiente. En el caso de que el sistema disponga más de un disco físico, cada uno será forzosamente un file system. Por lo tanto se puede asociar el concepto de sistema de archivos al de disco lógico o partición de disco.

          Es importante no perder la idea de que, aparte de otros componentes que se verán más adelante, cada sistema de archivos dispondrá de su propia tabla de i-nodos que apuntarán a los bloques de datos de los archivos y directorios contenidos en él.

          El sistema de archivos que contiene el directorio raíz (normalmente el primer disco o la primera partición del primer disco en su caso) es el principal. En principio, cuando se carga el sistema operativo, la única parte accesible de la estructura es la contenida en el file system principal. Para poder acceder a la información contenida en los restantes sistemas de operación es necesario realizar una operación denominada "montaje". Esta operación consiste en enlazar cada sistema de archivos con directorios vacíos de la estructura principal. A partir de ese momento, los archivos y directorios de los sistemas de archivos secundarios figurarán dentro de la estructura, colgando del directorio de montaje.

          Una vez montado todos los sistemas de archivos, la estructura es única, por lo que el disco o la partición en que esté físicamente un determinado archivo, es transparente para el usuario. La función de montaje y desmontaje de los sistemas de archivo es, normalmente, realizada por el administrador del sistema.

          El sistema de archivos, o file system, de UNIX está caracterizado por:

    • una estructura jerárquica,
    • tratamiento consistente de los datos,
    • la habilidad de crear y borrar archivos,
    • crecimiento dinámico de archivos,
    • la protección de los datos,
    • el tratamiento de los dispositivos periféricos como archivos.

          Cada sistema de archivos consta fundamentalmente de las siguientes partes:

    • Bloque de carga:
      Este bloque, que es el primero de cada sistema (bloque cero), está reservado para un programa de carga. El bloque cero no tiene ningún significado en el sistema de archivos. Toda la información del sistema comienza en el bloque uno del dispositivo. Sólo se utiliza en el sistema de archivos principal.
    • Súper bloque:
      El súper bloque es el bloque uno del dispositivo. Este bloque contiene información sobre el sistema de archivos, tales como su tamaño en bloques, el nombre del sistema de archivos, número de bloques reservados para i-nodos, la lista de i-nodos libres y el comienzo de la cadena de bloques libres. También contiene el nombre del volumen, momento de la última actualización y tiempo del último backup. Siempre reside en un bloque de 512 bytes.
    • I-nodos:
      A continuación del súper bloque están situados los bloques que contienen los i-nodos. El número de bloques de i-nodos varía dependiendo del número de bloques del sistema de archivos. El número de i-nodos está especificado en el súper bloque. Es una tabla que contiene información sobre las características de los archivos. Esencialmente es el bloque de control de los archivos. Hay un i-nodo por cada directorio y archivo del sistema de archivos. El i-nodo contiene una descripción del directorio o archivo, así como el lugar físico que ocupan sus bloques de datos. Los i-nodos sólo apuntan a los archivos o directorios de su mismo sistema de archivos.
    • Bloques de datos:
      El resto del espacio del dispositivo lógico consta de bloques de datos. Bloques de datos que contienen los datos actualmente almacenados en los archivos. Algunos bloques de datos sirven como bloques indirectos, conteniendo números de bloques (direcciones) de grandes archivos.

Figura 5. Estructura de un Sistema de Archivos.

          El sistema de archivos está organizado en una estructura jerárquica. Este sistema jerárquico permite agrupar la información de los usuarios de una forma lógica. Permite manipular eficientemente un grupo de archivos como una sola unidad. No tiene ninguna limitación en su desarrollo, permitiendo un crecimiento dinámico tanto en su número como en su tamaño. El UNIX trata a los archivos de entrada o de salida del mismo modo que cualquier otro archivo. Los usuarios deberán "caminar" a través del árbol hasta encontrar el archivo deseado. Dentro del UNIX el usuario puede acceder a cuatro clases de archivos:

    • Directorios.
    • Ordinarios.
    • Especiales.
    • Fifo (Pipes).

          Los directorios y los archivos ordinarios han sido ya comentados. Los archivos especiales se verán más adelante.



2.5 Manejo de los i-nodos:

          Cuando se intenta acceder a la información contenida en un archivo, el sistema accede al directorio al que pertenece y busca su nombre secuencialmente. Una vez encontrado toma el i-number asociado a ese archivo y con él accede a la entrada correspondiente a la tabla de i-nodos, que contendrá toda la información correspondiente a ese archivo excepto su nombre. Con esta información ya puede acceder físicamente a los bloques de datos dentro del sistema de archivos.

          Esta forma de acceder físicamente a los bloques de datos puede parecer más compleja que la utilizada en otros sistemas operativos en los que se accede directamente con la información existente en el directorio, sin necesidad de tablas de i-nodos ni nada por el estilo, sin embargo presenta algunas ventajas. Por ejemplo, si en un directorio se añade una entrada con un nombre de archivo cualquiera, pero con un i-number ya utilizado en otro directorio, se podrá acceder a los mismos bloques de datos desde los dos directorios e incluso con diferente nombres de archivos. En este caso se dice que existe un enlace entre ellos.

          El UNIX mantiene la siguiente información para cada archivo; en la tabla de i-nodos:

    • Localización.
    • Tamaño.
    • Cuántos enlaces tiene el archivo.
    • Propietario.
    • Permisos de acceso.
    • Identificación de si es o no archivo.
    • Fecha de creación.
    • Fecha de modificación.
    • Fecha de último acceso.

Figura 6. Contenido de un i-nodo.

          Además, cada i-nodo contiene diez punteros directos con la dirección de los diez primeros bloques de datos, un puntero indirecto simple con la dirección de un bloque que contiene punteros directos, que a su vez apuntan a bloques de datos; un puntero indirecto doble que apunta a un bloque con punteros indirectos simples, que apuntan a bloques con punteros directos y éstos a bloques de datos; y un puntero indirecto triple. En la figura 7 se ve un ejemplo gráfico de esta estructura.

Figura 7. Estructura de los punteros.


2.6 Archivos especiales:

          Además de los archivos normales de datos, dentro de la estructura de un sistema UNIX existen unos archivos especiales. Los nombres de estos archivos identifican los dispositivos físicos hardware del equipo:

    • Discos magnéticos
    • Cintas magnéticas
    • Terminales
    • Líneas de comunicaciones
    • Etc.

          Cada tipo de dispositivo tiene un controlador responsable de comunicarse con este dispositivo. Dentro del sistema hay una tabla que apunta a los diferentes controladores de los dispositivos. Todos los dispositivos son tratados como archivos. Existen archivos especiales para cada línea de comunicaciones, disco, unidad de cinta magnética, memoria principal, etc. Estos archivos en realidad están vacíos. Tienen por misión asociar entre sí los dispositivos y sus respectivos drivers. El sistema emplea dos números enteros, denominados número principal (14 bits) y número secundario (18 bits) y almacenados en el i-nodo del archivo, para acceder al dispositivo asociado.

          El número principal identifica una clase de dispositivo (en realidad identifica al driver de dicha clase como pueden ser terminales, impresoras, discos, etc.) y el número secundario identifica a un elemento de dicha clase (un terminal específico, un disco concreto, ...).

          Las ventajas de tratar las unidades de entrada/salida de esta forma son:

    • Los archivos y dispositivos son tratados lo más similarmente posible.
    • Los nombres de ambos son pasados a los programas de la misma forma.
    • Los archivos especiales están sujetos al mismo tipo de protección de acceso que los archivos y directorios ordinarios.
Figura 8. Relación de un archivo especial.


2.7 Principales directorios:

    /bin Contiene muchos de los archivos ejecutables correspondientes a los comandos.
    /usr/bin Contiene también ejecutables del mismo tipo.
    /usr/include         Contiene librerías de lenguaje C. Muy útil para los programadores.
    /dev Contiene archivos especiales asociados con dispositivos de entrada/salida.
    /etc Contiene entre otros, archivos ejecutables usados por el administrador.
    /tmp Utilizado para crear archivos temporales y de pruebas. Es borrado periódicamente por el sistema de forma automática.


2.8 Permisos de acceso de archivos y directorios:

      Cada archivo y directorio creado en UNIX tiene un propietario, normalmente la persona que lo ha creado. Ese propietario pertenece además a un grupo de usuarios. El propietario del archivo o directorio puede asignar varios tipos de permisos, para permitir o denegar el acceso al archivo o directorio. Los tipos de permisos de acceso son:

    Archivos:
      Lectura (r) Permitiría su acceso para lectura.
      Escritura (w) Permitiría su actualización.
      Ejecución (x)         Permite que el archivo pueda ser usado como comando shell.

    Directorios:

      Lectura (r) Permite ver su contenido.
      Escritura (w) Permite crear o borrar archivos bajo él.
      Ejecución (x)         Permite accederse a él.

      Cada usuario puede especificar el permiso de acceso a sus archivos, seleccionando la adecuada combinación de tipos de permisos, con el fin de permitir o denegar el acceso a tres niveles de usuarios (propietario, usuarios de su grupo, y el resto de usuarios).




3. Control de procesos

          Un programa es un archivo ejecutable, y un proceso es una instancia del programa en ejecución. En UNIX pueden ejecutarse varios procesos simultáneamente (esta característica es denominada algunas veces como multiprogramación o multitarea) sin un límite lógico en el número de ellos, y varias instancias del mismo programa pueden existir simultáneamente en el sistema. Algunas llamadas al sistema permiten a los procesos crear nuevos procesos, acabar procesos, sincronizar niveles de ejecución de procesos y controlar la reacción de algunos sucesos. Sujeto a sus propias llamadas al sistema, los procesos son independientes de los demás.

          Generalmente, las llamadas al sistema permiten al usuario escribir programas que realicen sofisticadas operaciones, y como resultado, el kernel del sistema UNIX no contiene muchas funciones que son parte del "kernel" en otros sistemas. Estos programas, incluyendo compiladores y editores, son programas a nivel de usuario en el sistema UNIX. El principal ejemplo de estos programas es el shell, el intérprete de comandos que los usuarios ejecutan normalmente de entrar en el sistema.

          El núcleo del sistema operativo UNIX conoce la existencia de un proceso a través de su bloque de control del proceso, donde se describe el proceso y su entorno, constituyendo un contexto consistente en:

    • Espacio de direccionamiento y entorno de ejecución: Variables que utiliza el proceso.
    • Contenido de los registros hardware: Contador de programa, registro de estado del procesador, puntero de la pila y registros de propósito general.
    • Contenido de las estructuras del núcleo relacionadas con el proceso: Tabla de proceso, áreas, regiones, etc.

          Si congelamos el estado del procesador y del proceso que está en ejecución en un determinado momento, obtendríamos lo que se conoce como imagen estática del programa. En caso de producirse una interrupción o cambio de proceso, se almacena la imagen del que está en ejecución en ese mismo instante.

          Cada proceso se reconoce dentro del sistema por un número que lo identifica unívocamente y que se conoce como Identificador del Proceso o PID.

          Todos los procesos, excepto el proceso 0, son creados por otro proceso; es decir, el sistema de creación y gestión de procesos en UNIX es jerárquico.

          El proceso que se genera con el PID 0 es un proceso especial creado en el momento de arrancar el sistema. A continuación se genera un proceso init que será el antecesor de todos los procesos que se generen en el sistema. A partir de aquí se generan tantos procesos como terminales existan (se dará una descripción más adelante).

          Los procesos que atienden a los terminales crearan otros con el fin de identificar y controlar el acceso de los usuarios al sistema, los cuales, una vez que inicien la sesión, ejecutarán un proceso intérprete de comandos Shell que será el que genere el resto de programas solicitados por el usuario.






4. Servicios del sistema operativo

          En la figura 1 se mostraba el nivel del kernel inmediatamente por debajo del nivel de los programas del usuario (a.out). La estructura del kernel venía detallada en la figura 2. El kernel ejecuta varias operaciones primitivas en apoyo de los procesos del usuario para soportar la interface de usuario descrita arriba. Entre los servicios que suministra el kernel están:

    • Control de la ejecución de procesos permitiendo su creación, finalización o suspensión y comunicación.
    • Planificación justa de los procesos para su ejecución en la CPU. Los procesos comparten la CPU por el método de tiempo compartido: la CPU ejecuta un proceso, el kernel lo suspende cuando su cuantum de tiempo se acaba y el kernel planifica otro proceso para su ejecución. El kernel después replanifica el proceso suspendido.
    • Asignación de memoria principal a los procesos en ejecución. El kernel asigna a los procesos compartir partes de su espacio de direcciones bajo ciertas condiciones, pero protege el espacio de direcciones privado del proceso de accesos exteriores. Si el sistema se está ejecutando con poca memoria libre, el kernel libera memoria escribiendo un proceso temporalmente en la memoria secundaria, llamada área de swap. Si el kernel escribe un proceso entero en el área de swap, la implementación del sistema UNIX se denomina sistema de swapping; si escribe páginas de memoria, se denomina sistema paginado.
    • Asignación de memoria secundaria para almacenamiento y recuperación de datos eficiente. Este servicio constituye el sistema de archivos. El kernel asigna almacenamiento secundario para los archivos de usuario, pidiendo zonas sin usar, estructurando el sistema de archivos de una manera comprensible y protegiendo los datos de accesos ilegales.
    • Asignación a los procesos accesos controlados de los dispositivos periféricos tales como terminales, controladores de cinta, controladores de disco y dispositivos de red.

          El kernel suministra estos servicios de una forma transparente al usuario. Por ejemplo, reconoce que un archivo dado es un archivo regular o un dispositivo, pero oculta la distinción a los procesos de usuario. De forma análoga, formatea los datos en un archivo para su almacenamiento interno, pero oculta el formato interno a los procesos de usuario, devolviendo un flujo de bytes.






5. Consideraciones sobre el hardware

          La ejecución de procesos de usuario en sistemas UNIX se divide en dos niveles: usuario y kernel. Cuando un proceso ejecuta una llamada al sistema, el modo de ejecución cambia del modo usuario a modo kernel: el sistema operativo ejecuta y atiende el servicio requerido por el usuario, devolviendo un código de error si falla. Incluso si el usuario no hace una petición explícita de los servicios del sistema operativo, el sistema operativo continúa realizando operaciones que relacionan a los procesos de usuario, manipulando interrupciones, planificando procesos, administrando la memoria, etc. Muchas arquitecturas (y sus sistemas operativos) soportan más niveles que los dos descritos, pero estos dos modos, usuario y kernel, son suficientes para los sistemas UNIX.

          Las diferencias entre los dos modos son:

    • Los procesos en el modo usuario pueden acceder a sus propias instrucciones y datos pero no a las instrucciones y datos del kernel (o los de otros procesos). Los procesos en el modo kernel, sin embargo, pueden acceder a las direcciones del kernel y del usuario.
    • Algunas instrucciones máquina están privilegiadas y producen error si se ejecutan en modo usuario.


5.1 Interrupciones y excepciones:

          El sistema UNIX permite a dispositivos tales como los periféricos de entrada/salida o el reloj del sistema interrumpir la CPU asíncronamente. Al recibir una interrupción, el kernel salva el contexto (una imagen de lo que el proceso estaba haciendo), determina la causa de la interrupción y la atiende. Después de que el kernel atienda a la interrupción, restaura el entorno y el proceso interrumpidos como si no hubiese pasado nada. El hardware normalmente asigna prioridades a los dispositivos según el orden que se quiera dar a las interrupciones para manejarlas: cuando el kernel atiende a una interrupción, bloquea las interrupciones con menor prioridad pero atiende a las interrupciones con mayor prioridad.

          Una condición de excepción se refiere a eventos inesperados causados por un proceso, como un direccionamiento ilegal a memoria, ejecución de instrucciones privilegiadas, división por cero, etc. Son distintas de las interrupciones, las cuales están causadas por eventos externos al proceso. Las excepciones suceden en mitad de la ejecución de una instrucción y el sistema intenta restaurar la instrucción después de manejar la excepción; las interrupciones suceden entre la ejecución de dos instrucciones y el sistema continúa con la siguiente instrucción después de atender la interrupción. El sistema UNIX usa un mecanismo para manejar interrupciones y condiciones de excepción.



5.2 Niveles de ejecución:

          El kernel debe normalmente prevenir una interrupción durante una actividad crítica, lo cual puede resultar en datos erróneos si la interrupción tiene lugar. Por ejemplo, el kernel no debe querer recibir una interrupción de disco mientras está manipulando listas enlazadas, porque el atender a la interrupción puede corromper los punteros. Las computadoras normalmente tienen un conjunto de instrucciones privilegiadas que colocan el nivel de ejecución de procesos en el estado del proceso. Colocando el nivel de ejecución de procesos a unos determinados valores se inhabilitan las interrupciones desde un nivel hacia abajo, permitiendo sólo las interrupciones de un nivel superior. La figura 9 muestra un ejemplo de un conjunto de niveles de ejecución. Si el kernel inhabilita las interrupciones de disco, todas las interrupciones excepto las interrupciones de reloj y las de error de máquina están inhabilitadas. Si se inhabilita las interrupciones de software, todas las demás pueden ocurrir.

Figura 9. Ejemplo de prioridades de las interrupciones.


5.3 Administración de la memoria:

          La gestión de memoria en UNIX se basa en intercambio (swapping) y paginación.

      Swapping:
      El área de swap se comporta como una ampliación de la memoria principal. Cuando ésta se va llenando con los procesos activos, aquellos con más baja prioridad son desplazados al área de swap. Cuando adquieren una prioridad superior a alguno de los que están en memoria, éstos se desplazan al área de swap y los otros vuelven a cargarse en memoria.
      Paginación:
      La paginación de la memoria se lleva a cabo si el hardware de la computadora la soporta. El espacio de direcciones de un programa se divide en unidades llamadas páginas. Las unidades correspondientes en la memoria física se denominan cuadros de página. Las páginas y los cuadros de página siempre son del mismo tamaño. Las transferencias entre la memoria y el disco siempre están en unidades de una página. Se mantienen en memoria principal las páginas que están usando los procesos activos. Si un programa direcciona una página que no está en memoria principal, se produce una falta de página. El sistema operativo toma un cuadro de página con poco uso y vuelve a escribir su contenido en el disco. Después captura la página recién referida en el cuadro de página que acaba de liberarse.

          El kernel permanentemente reside en la memoria principal al igual que lo hace el proceso que se está ejecutando actualmente. Cuando se compila un programa, el compilador genera una serie de direcciones en el programa que representan direcciones de variables y estructuras de datos o las direcciones de instrucciones tales como las funciones. El compilador genera las direcciones para una máquina virtual como si no se ejecutara ningún otro programa simultáneamente en la máquina real.

          Cuando el programa está ejecutándose en la máquina, el kernel asigna espacio en la memoria principal para él, pero las direcciones virtuales generadas por el compilador no necesitan coincidir con las direcciones físicas que ocupan en la máquina. El kernel coordina con el hardware la conversión de las direcciones virtuales generadas por el compilador a las direcciones físicas de la máquina.