domingo, 17 de octubre de 2010

2.5 Perspectiva general de procesos en MINIX

A diferencia de UNIX cuyo núcleo es un programa monolítico, MINIX es un núcleo formado por una colección de proceso que se comunican entre sí y con los proceso de usuario mediante una única primitiva de comunicación interproceso: transferencia de mensajes. Este diseño proporciona una estructura más modular y flexible, lo cual hace que sea sencillo, por ejemplo, cambiar completamente el sistema de archivos sin que sea necesario ni siquiera recompilar el kernel.

La estructura interna de MINIX

MINIX se encuentra estructurado en cuatro capas, cada una de estas capas realiza una función que tiene definida.

El kernel en la capa inferior planifica los proceso y gestiona las transiciones entre los estados listo, corriendo y bloqueado. El kernel maneja también los mensajes entre proceso. El kernel también se ocupa de asistir en el acceso a los puertos de E/S y a las interrupciones, lo cual en los procesadores modernos requiere el uso de instrucciones privilegiadas de modo kernel que no están disponibles para los proceso ordinarios.

Una de las principales funciones de la capa 1 es proporcionar un conjunto de llamadas al kernel para que usen los drivers y servers que están por encima. Entre ellas tenemos la lectura y escritura de puertos de E/S el copiado de datos entre diferentes espacios de direcciones, etc. La implementación de estas llamadas está en la tarea del sistema. Aunque la tarea del sistema y la tarea del reloj están compiladas dentro del espacio de direcciones del kernel, se planifican como proceso separados y tienen sus propias pilas de llamadas (call stack).

La mayor parte del kernel y de las tareas del sistema y del reloj están escritas en lenguaje C.

Los proceso en capa 2 tienen la mayoría de los privilegios, aquellos de capa 3 tienen algunos privilegios, y los de capa 4 no tienen ningún privilegio. Por ejemplo los proceso en capa 2 que se denominan controladores de dispositivo (device drivers), tienen permitido realizar solicitudes a la tarea del sistema para que lea o escriba datos de los puertos de E/S a su favor. Se necesita un controlador para cada tipo de dispositivo: discos, impresoras, terminales, interfaces de red, etc. Los controladores de dispositivo pueden hacer otras llamadas al kernel, como por ejemplo que los datos recien leídos se copien al espacio de direcciones de otro proceso.

La capa 3 contiene proceso que proporcionan servicios que le son útiles a los usuarios.

La tercera capa contiene los servers, que son procesos que proporcionan servicios útiles a los procesos de usuario. Hay dos servidores esenciales. El process manager (PM) lleva adelante las llamadas al sistema de MINIX que involucran el arranque y detención de procesos tales como fork, exec y exit, y las llamadas relacionadas con las señales, como alarm y kill, que pueden alterar el estado de los procesos. El proceso manager también es responsable de gestionar la memoria con la llamada al sistema brk. El file system (FS) se ocupa de todas las llamadas al sistema de archivos, como read, mount y chdir.

Las llamadas al kernel son funciones de bajo nivel provistas por la tarea del sistema como servicio a drivers y servers. La lectura de un puerto de E/S es una llamada al kernel típica. Las llamadas al sistema POSIX como read, fork y unlink son llamadas de alto nivel definidas en el estándar POSIX y que están disponibles para los programas de usuario en la capa 4. Los programas de usuario pueden hacer llamadas POSIX pero no pueden hacer llamadas al kernel.

La capa 4 (superior) contiene todos los proceso de usuario: Shell, editores, compiladores, y programas a.out escritos por el usuario.

Por último, la capa 4 contiene todos los procesos de usuario: el shell, editores, compiladores y todos los programas a.out escritos por los usuarios. Un sistema en peración tiene algunos procesos que vienen y van a medida que los usuarios ingresan, trabajan y se desconectan. Otros procesos se inician con el sistema y perduran, como init, y también habrá varios demonios. Un demonio es un proceso en segundo plano que se se ejecuta periódicamente o que siempre espera por alguna clase de evento, com por ejemplo el arribo de un paquete por la interfaz de red. En cierto sentido, un demonio es un server que se inicia independientemente y corre como proceso de usuario.

Administración de proceso en MINIX

Los procesos en MINIX pueden crear otros procesos y ellos a su vez otros más, lo cual no da un árbol de procesos, del cual init es la raíz. Los servers y los drivers son casos especiales pues algunos de ellos deben iniciarse antes de cualquier proceso de usuario, incluso antes de init.

Cuando se enciende la computadora, el hardware lee en memoria el primer sector de la primer pista del disco de arranque y ejecuta el código que encuentra allí. En un disquete este sector contiene el programa de bootstrap. Es muy pequeño, pues debe caber en un sector (512 bytes). El bootstrap de MINIX carga un programa mayor, denominado boot, cuya misión es cargar el SO en sí mismo.

El caso de los discos rígidos es diferente y requiere un paso intermedio. El disco rígido se divide en particiones, y el primer sector del disco contiene un pequeño programa y la tabla de particiones. Colectivamente a esas dos partes se las denomina master boot record. El pequeño programa del primer sector se ejecuta para leer la tabla de particiones y seleccionar la partición activa. La partición activa tiene un bootstrap en su primer sector, el cual se carga y se ejecuta para arrancar la copia de boot en esa partición, exactamente como se hace cuando se arranca desde disquete.

Durante la fase de inicialización el kernel arranca la tarea del sistema y la tarea del reloj, y luego el PM y el FS. El PM y el FS cooperan luego para iniciar los otros servers y drivers que forman parte de la imagen de arranque, Cuando todos han funcionado y se han inicializado, se bloquean a la espera de algo para hacer.

service es la interfaz de usuario del RS. El RS arranca un programa ordinario y lo convierte en un proceso del sistema.

Las dos llamadas al sistema principales en MINIX para la gestión de procesos son fork y exec. fork es la única manera de crear un nuevo proceso. exec permite que un proceso ejecute un determinado programa. Cuando un programa se ejecuta se le asigna una porción de memoria cuyo tamaño se especifica en la cabecera del archivo del programa. El proceso mantiene como propia a dicha cantidad de memoria durante toda su ejecución, si bien la distribución entre segmento de datos, segmento de pila y espacio sin usar puede variar en el tiempo.

Toda la información sobre el proceso se mantiene en la tabla de procesos, que está divdida entre el kernel, el PM, y el FS, de manera que cada uno de ellos tiene los campos de la tabla que necesita. Cuando un nuevo proceso viene a la existencia (por fork), o cuando uno viejo termina (por exit o una señal), el PM actualiza primero su parte de la tabla de proceso y luego envía mensajes al fs y al kernel para pedirles que hagan lo mismo.

Comunicación entre proceso en MINIX

Se proporcionan tres primitivas para enviar y recibir mensajes, las cuales se pueden llamar mediante procedimientos de la biblioteca C:

  • send(dest, &message); para enviar un mensaje al proceso dest.
  • receive(source, &message); para recibir un mensaje del proceso source (o ANY).
  • Send_rec(src_dst, &message); para enviar un mensaje y esperar la respuesta del mismo proceso.

El segundo parámetro de los mensajes es la dirección local de los datos del mensaje. El mecanismo de pasaje de mensajes en el kernel copia el mensaje desde el emisor hacia el receptor. La respuesta (para Send_rec) sobrescribe el mensaje original. En principio este mecanismo del kernel se podría sustituir por una función que copie los mensajes sobre una red a la función correspondiente en otra máquina, para implemetar un sistema distribuído. En la práctica, esto se vería algo complicado por el hecho de que el contenido del mensaje algunas veces incluye punteros a estructuras de datos de gran tamaño, y entonces el sistema distribuído debería realizar la copia de esos datos también a través de la red.

Cada tarea, driver o proceso tiene permitido el intercambio de mensajes sólo con ciertos procesos. El flujo usual de mensajes es hacia abajo en las capas, y los mensajes pueden ser entre proceso de la misma capa o entre proceso de capas adyacentes. Los procesos de usuario no pueden enviarse mensajes entre sí.

Cuando un proceso envía un mensaje a otro proceso que no lo está esperando, el emisor se bloquea hasta que el receptor hace un receive. En otras palabras, en MINIX se usa el método cita para evitar el problema del buffering de los mensajes enviados pero aún no recibidos. La ventaja de este enfoque es que es simple y elimina la gestión de los buffers (incluso que se acabe el espacio de buffers). Además, como todos los mensajes son de tamaño fijo, determinado al momento de compilación, se previenen en forma estructural los errores causados por la escritura fuera de un buffer.

Existen otras primitivas relacionadas con la comunicación interproceso, pero son menos importantes que send, receive, sendrec, y notify.

Planificación de proceso en MINIX

La planificación de proceso en MINIX tiene prioridades, como tareas, administración de memoria servidor de archivos comparten la misma prioridad y los proceso de usuario.

El sistema de interrupciones es lo que mantiene en operación a un SO multiprogramación. Los procesos se bloquean cuando hacen solicitudes de entrada y de esa manera permiten que otros proceso se ejecuten. Cuando se dispone de la entrada lista, el proceso que está corriendo es interrumpido por el disco, teclado u otro hardware. El reloj también se usa para generar interrupciones que se usan para asegurar que los procesos que no solicitan entradas eventualmente suelten la CPU, para dar oportunidad a otros procesos de que corran. Las capas más bajas de MINIX tienen la función de ocultar esas interrupciones y transformarlas en mensajes. En cuanto a los proceso concierne, cuando un dispositivo de E/S completa una operación, le envía un mensaje a un proceso, despertándolo y tornándolo elegible para correr.

Cada vez que se interrumpe un proceso (por un dispositivo de E/S convencional, o por el reloj, o a causa de una interrupción de software) existe la oportunidad de determinar cuál de los procesos es el que merece disponer de la CPU. Claro que esto también se hace cuando un proceso termina, pero en un sistema como MInIX es más frecuente que ocurran interrupciones de E/S, del reloj o pasaje de mensajes, que terminaciones de proceso.

En cada tic del reloj se verifica para saber si el proceso actual ha corrido por más tiempo del quantum que tenía asignado. Si eso sucede, el planificador lo mueve al final de su cola (lo cual no requiere nada de esfuerzo si es el único en la cola). Luego se elige el siguiente proceso, como se describió más arriba. El proceso desalojado vuelve a correr inmediatamente solamente en el caso que esté solo en su cola y que no haya ningún proceso listo en las colas de mayor prioridad. Si no, el proceso que corre es el que está a la cabeza de la cola no vacía de mayor prioridad. Los drivers y los server esenciales disponen de quanta tan largos que normalmente nunca son desalojados por el reloj.

No hay comentarios:

Publicar un comentario