Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
Fundamentos de sistemas operativos Séptima edición Fundamentos de sistemas operativos Séptima edición ABRAHAM SILBERSCHATZ Yale University PETER BAER GALVIN Corporate Technologies, Inc. GREG GAGNE W estminster College Traducción VUELAPLUMA, S. L. Revisión técnica JESÚS SÁNCHEZ ALLENDE Doctor Ingeniero de Telecomunicación Dpto. de Electrónica y Sistemas Universidad Alfonso X El Sabio M e G r a w Hill MADRID BOGOTA • BUENOS AIRES • CARACAS • GUATEMALA • LISBOA MÉXICO • NUEVA YORK • PANAMÁ • SAN JUAN • SANTIAGO • SAO PAULO AUCKLAND • HAMBURGO • LONDRES • MILÁN • MONTREAL • NUEVA DELHI • PARÍS SAN FRANCISCO • SIDNEY • SINGAPUR • ST. LOUIS • TOKIO • TORONTO La inform ación contenida en este libro procede de una obra original publicada por John W iley & Sons, Inc. N o ob s tante, M cGraw-Hill/Interam ericana de España no garantiza la exactitud o perfección de la inform ación publicada. Tam poco asum e ningún tipo de garantía sobre los contenidos y las opiniones vertidas en dichos textos. E ste trabajo se publica con el reconocim iento expreso de que se está proporcionando una inform ación, pero no tra tando de prestar ningún tipo de servicio profesional o técnico . L os procedim ientos y la inform ación que se presen tan en este libro tienen sólo la intención de servir com o guía general. M cG raw -H ill ha solicitado los permisos oportunos para la realización y el desarrollo de esta obra. FUNDAMENTOS DE SISTEMAS OPERATIVOS, T EDICIÓN N o está permitida la reproducción total o parcial de este libro/ni su tratamiento inform ático, ni la transmisión de ninguna form a o por cualquier m edio, ya sea e lectrón ico , m ecánico , por fotocopia, por registro u otros m étodos, sin el perm iso previo y por escrito de los titulares del Copyright. McGraw-Hill / Interamericana de España, S. A. U. D E R E C H O S R ESER V A D O S © 2 0 0 6 , respecto a la séptim a edición en español, por M cG R A W -H IL L/ lN T ER A M E R IC A N A D E ESP A Ñ A , S. A . U. E dificio Valrealty, Ia planta Basauri, 17 2 8 0 2 3 Aravaca (M adrid) http://www. mcgraw-hill. es universidad&mcgraw-hill.com Traducido de la séptima edición en inglés de OPERATING SYSTEM CONCEPTS IS B N : 0 -4 7 1 -6 9 4 6 6 -5 Copyright © 2005 por John W iley & Sons, Inc. IS B N : 8 4 -4 8 1 -4 6 4 1 -7 D epósito legal: M. 7 .9 5 7 -2 0 0 6 Editor: Carm elo Sánchez González Com puesto por: Vuelapluma, S. L. Im preso en: C ofas. S . A. IM P R E S O EN ESPAÑ A - P R IN TE D 1N SPAIN M e Graw Hill http://www A mi hijos, Lemor, Sivan y Aaron Avi Silberschatz A mi esposa Carla, y a mis hijos, Gioen Owen y Maddie Peter Baer Galvin A la memoria del tío Sonny, Robert Jon Heileman 1933 -2 0 0 4 Greg Gagne Estructuras de sistemas operativos Un sistema operativo proporciona el entorno en el que se ejecutan los programas. Internamente, los sistemas operativos varían mucho en su composición, dado que su organización puede anali zarse aplicando múltiples criterios diferentes. El diseño de un nuevo sistema operativo es una tarea de gran envergadura, siendo fundamental que los objetivos del sistema estén bien definidos antes de comenzar el diseño. Estos objetivos establecen las bases para elegir entre diversos algo ritmos y estrategias. Podemos ver un sistema operativo desde varios puntos de vista. Uno de ellos se centra en los servicios que el sistema proporciona; otro, en la interfaz disponible para los usuarios y programa- dores; un tercero, en sus componentes y sus interconexiones. En este capítulo, exploraremos estos tres aspectos de los sistemas operativos, considerando los puntos de vista de los usuarios, progra madores y diseñadores de sistemas operativos. Tendremos en cuenta qué servicios proporciona un sistema operativo, cómo los proporciona y las diferentes metodologías para diseñar tales sis temas. Por último, describiremos cómo se crean los sistemas operativos y cómo puede una com putadora iniciar su sistema operativo. OBJETIVOS DEL CAPÍTULO • Describir los servicios que un sistema operativo proporciona a los usuarios, a los procesos y a otros sistemas. • Exponer las diversas formas de estructurar un sistema operativo. • Explicar cómo se instalan, personalizan y arrancan los sistemas operativos. 2.1 Servicios del sistema operativo Un sistema operativo proporciona un entorno para la ejecución de programas. El sistema presta ciertos servicios a los programas y a los usuarios de dichos programas. Por supuesto, los servicios específicos que se suministran difieren de un sistema operativo a otro, pero podemos identificar perfectamente una serie de clases comunes. Estos servicios del sistema operativo se proporcionan para comodidad del programador, con el fin de facilitar la tarea de desarrollo. Un cierto conjunto de servicios del sistema operativo proporciona funciones que resultan úti les al usuario: • Interfaz de usuario. Casi todos los sistemas operativos disponen de una interfaz de usua rio (UI, user interface), que puede tomar diferentes formas. Uno de ios tipos existentes es la interfaz de línea de com andos (CLI, command-line interface), que usa comandos de textos y algún tipo de método para introducirlos, es decir, un programa que permite introducir y editar los comandos. Otro tipo destacabíe es la interfaz de proceso por lotes, en la qüe los Capítulo 2 Estructuras de sistemas operativos comandos y las directivas para controlar dichos comandos se introducen en archivos, \ luego dichos archivos se ejecutan. Habitualmente, se utiliza una interfaz gráfica de usuario (GUI, graphical user interface); en este caso, la interfaz es un sistema de ventanas, con un dispositivo señalador para dirigir la E/S, para elegir opciones en los menús y para realizar otras selecciones, y con un teclado para introducir texto. Algunos sistemas proporcionan dos o tres de estas variantes. • Ejecución de programas. El sistema tiene que poder cargar un programa en memoria y eje cutar dicho programa. Todo programa debe poder terminar su ejecución, de forma normal o anormal (indicando un error). • Operaciones de p/S. Un programa en ejecución puede necesitar llevar a cabo operaciones de E /S , dirigidas a un archivo o a un dispositivo de E /S . Para ciertos dispositivos específi cos, puede ser deseable disponer de funciones especiales, tales como grabar en una unidad de CD o DVD o borrar una pantalla de TRC (tubo de rayos catódicos). Por cuestiones de efi ciencia y protección, los usuarios no pueden, normalmente, controlar de modo directo los dispositivos de E /S ; por tanto, el sistema operativo debe proporcionar medios para realizar la E /S . • Manipulación del sistema de archivos. El sistema de archivos tiene una importancia espe cial. Obviamente, los programas necesitan leer y escribir en archivos y directorios. También necesitan crearlos y borrarlos usando su nombre, realizar búsquedas en un determinado archivo o presentar la información contenida en un archivo. Por último, algunos programas incluyen mecanismos de gestión de permisos para conceder o denegar el acceso a los archi vos o directorios basándose en quién sea el propietario del archivo. • Comunicaciones. Hay muchas circunstancias en las que un proceso necesita intercambiar información con otro. Dicha comunicación puede tener lugar entre procesos que estén eje cutándose en la misma computadora o entre procesos que se ejecuten en computadoras diferentes conectadas a través de una red. Las comunicaciones se pueden implementar uti lizando memoria compartida o mediante paso de mensajes, procedimiento éste en el que el sis tema operativo transfiere paquetes de información entre unos procesos y otros. • Detección de errores. El sistema operativo necesita detectar constantemente los posibles errores. Estos errores pueden producirse en el hardware del procesador y de memoria (como, por ejemplo, un error de memoria o un fallo de la alimentación) en un dispositivo de E/S(como un error de paridad en una cinta, un fallo de conexión en una red o un pro blema de falta papel en la impresora) o en los programas de usuario (como, por ejemplo, un desbordamiento aritmético, un intento de acceso a una posición de memoria ilegal o un uso excesivo del tiempo de GPU). Para cada tipo de error, el sistema operativo debe llevar a cabo la acción apropiada para asegurar un funcionamiento correcto y coherente. Las facilidades de depuración pueden mejorar en gran medida la capacidad de los usuarios y programado- res para utilizar el sistema de manera eficiente. Hay disponible otro conjunto de funciones del sistema de operativo que no están pensadas para ayudar al usuario, sino para garantizar la eficiencia del propio sistema. Los sistemas con múltiples usuarios pueden ser más eficientes cuando se comparten los recursos del equipo entre los distintos usuarios: • Asignación de recursos. Cuando hay varios usuarios, o hay varios trabajos ejecutándose al mismo tiempo, deben asignarse a cada uno de ellos los recursos necesarios. El sistema operativo gestiona muchos tipos diferentes de recursos; algunos (como los ciclos de CPU, la memoria principal y el espacio de almacenamiento de archivos) pueden disponer de códi go software especial que gestione su asignación, mientras que otros (como los dispositivos de E/S) pueden tener código que gestione de forma mucho más general su solicitud y libe ración. Por ejemplo, para poder determinar cuál es el mejor modo de usar la CPU, el siste ma operativo dispone de rutinas de planificación de la CPU que tienen en cuenta la veloci dad del procesador, los trabajos que tienen que ejecutarse, el número de registros disponi- 2.2 Interfaz de usuario del sistema operativo 37 bles y otros factores. También puede haber rutinas para asignar impresoras, modems, uni dades de almacenamiento USB y otros dispositivos periféricos. • R esponsabilidad. Normalmente conviene hacer un seguimiento de qué usuarios emplean qué clase de recursos de la computadora y en qué cantidad. Este registro se puede usar para propósitos contables (con el fin de poder facturar el gasto correspondiente a los usuarios) o simplemente para acumular estadísticas de uso. Estas estadísticas pueden ser una herra mienta valiosa para aquellos investigadores que deseen reconfigurar el sistema con el fin de mejorar los servicios informáticos. • Protección y seguridad. Los propietarios de la información almacenada en un sistema de computadoras en red o multiusuario necesitan a menudo poder controlar el uso de dicha información. Cuando se ejecutan de forma concurrente varios procesos distintos, no debe ser posible que un proceso interfiera con los demás procesos o con el propio sistema opera tivo. La protección implica asegurar que todos los accesos a los recursos del sistema estén controlados. También es importante garantizar la seguridad del sistema frente a posibles intrusos; dicha seguridad comienza por requerir que cada usuario se autentique ante el sis tema, usualmente mediante una contraseña, para obtener acceso a los recursos del mismo. Esto se extiende a la defensa de los dispositivos de E/S, entre los que se incluyen modems y adaptadores de red, frente a intentos de acceso ilegales y el registro de dichas conexiones con el fin de detectar intrusiones. Si hay que proteger y asegurar un sistema, las proteccio nes deben implementarse en todas partes del mismo: una cadena es tan fuerte como su esla bón más débil. 2.2 Interfaz de usuario del sistema operativo Existen dos métodos fundamentales para que los usuarios interactúen con el sistema operativo. Una técnica consiste en proporcionar una interfaz de línea de comandos o intérprete de com an dos, que permita a los usuarios introducir directamente comandos que el sistema operativo pueda ejecutar. El segundo método permite que el usuario interactúe con el sistema operativo a través de una interfaz gráfica de usuario o GUI. 2.2.1 Intérprete de comandos Algunos sistemas operativos incluyen el intérprete de comandos en el kernel. Otros, como Windows XP y UNIX, tratan al intérprete de comandos como un programa especial que se ejecuta cuando se inicia un trabajo o cuando un usuario inicia una sesión (en los sistemas interactivos). En los sistemas que disponen de varios intérpretes de comandos entre los que elegir, los intérpre tes se conocen como shells. Por ejemplo, en los sistemas UNIX y Linux, hay disponibles varias shells diferentes entre las que un usuario puede elegir, incluyendo la shell B ourne, la she ll C, la shell B o im ie -A g a in , la shell K o rn , etc. La mayoría de las shells proporcionan funcionalidades similares, existiendo sólo algunas diferencias menores, casi todos los usuarios seleccionan una she ll u otra basándose en sus preferencias personales. La función principal del intérprete de comandos es obtener y ejecutar el siguiente comando especificado por el usuario. Muchos de los comandos que se proporcionan en este nivel se utili zan para manipular archivos: creación, borrado, listado, impresión, copia, ejecución, etc.; las shells de MS-DOS y UNIX operan de esta forma. Estos comandos pueden implementarse de dos formas generales. Uno de los métodos consiste en que el propio intérprete de comandos contiene el código que el comando tiene que ejecutar. Por ejemplo, un comando para borrar un archivo puede hacer que el intérprete de comandos salte a una sección de su código que configura los parámetros nece sarios y realiza las apropiadas llamadas al sistema. En este caso, el número de comandos que puede proporcionarse determina el tamaño del intérprete de comandos, dado que cada comando requiere su propio código de implementación. Capítulo 2 Estructuras de sistemas operativos Un método alternativo, utilizado por UNIX y otros sistemas operativos, implementa la mayoría de los comandos a través de una serie de programas del sistema. En este caso, el intérprete de comandos no “entiende” el comando, sino que simplemente lo usa para identificar el archivo que hay que cargar en memoria y ejecutar. Por tanto, el comando UNIX para borrar un archivo rm f i l e . t x t buscaría un archivo llamado rm, cargaría el archivo en memoria y lo ejecutaría, pasándole el pará metro f i l e . t x t . La función asociada con el comando rm queda definida completamente mediante el código contenido en el archivo rm. De esta forma, los programadores pueden añadir comandos al sistema fácilmente, creando nuevos archivos con los nombres apropiados. El progra ma intérprete de comandos, que puede ser pequeño, no tiene que modificarse en función de los nuevos comandos que se añadan. 2.2.2 Interfaces gráficas de usuario Una segunda estrategia para interactuar con el sistema operativo es a través de una interfaz grá fica de usuario (GUI) suficientemente amigable. En lugar de tener que introducir comandos direc tamente a través de la línea de comandos, una GUI permite a los usuarios emplear un sistema de ventanas y menús controlable mediante el ratón. Una GUI proporciona una especie de escritorio en el que el usuario mueve el ratón para colocar su puntero sobre imágenes, o iconos, que se muestran en la pantalla (el escritorio) y que representan programas, archivos, directorios y fun ciones del sistema. Dependiendo de la ubicación del puntero, pulsar el botón del ratón puede invocar un programa, seleccionar un archivo o directorio (conocido como carpeta) o desplegar un menú que contenga comandos ejecutables. Las primeras interfaces gráficas de usuario aparecieron debido, en parte, a las investigaciones realizadas en el departamento de investigación de Xerox Pare a principios de los años 70. La pri mera GUI se incorporó en la computadora Xerox Alto en 1973. Sin embargo, las interfaces gráficas sólo se popularizaron con la introducción de las computadoras Apple Macintosh en los años 80. La interfaz de usuario del sistema operativo de Macintosh (Mac OS) ha sufrido diversos cambiosa lo largo de los años, siendo el más significativo la adopción de la interfaz Aqua en Mac OS X. La primera versión de Microsoft Windows (versión 1.0) estaba basada en una interfaz GUI que per mitía interactuar con el sistema operativo MS-DOS. Las distintas versiones de los sistemas Windows proceden de esa versión inicial, a la que se le han aplicado cambios cosméticos en cuan to su apariencia y diversas mejoras de funcionalidad, incluyendo el Explorador de Windows. Tradicionalmente, en los sistemas UNIX han predominado las interfaces de línea de comandos, aunque hay disponibles varias interfaces GUI, incluyendo el entorno de escritorio CDE (Common Desktop Environment) y los sistemas X-Windows, que son muy habituales en las versiones comerciales de UNIX, como Solaris o el sistema AIX de IBM. Sin embargo, también es necesario resaltar el desarrollo de diversas interfaces de tipo GUI en diferentes proyectos de código fuente abierto, como por ejemplo el entorno de escritorio KDE (K Desktop Environment) y el entorno GNOME, que forma parte del proyecto GNU. Ambos entornos de escritorio, KDE y GNOME, se ejecutan sobre Linux y otros varios sistemas UNIX, y están disponibles con licencias de código fuente abierto, lo que quiere decir que su código fuente es del dominio público. La decisión de usar una interfaz de línea de comandos o GUI es, principalmente, una opción personal. Por regla general, muchos usuarios de UNIX prefieren una interfaz de línea de coman dos, ya que a menudo les proporciona interfaces de tipo shell más potentes. Por otro lado, la mayor parte de los usuarios de Windows se decantan por el uso del entorno GUI de Windows y casi nunca emplean la interfaz de tipo shell MS-DOS. Por el contrario, los diversos cambios experimen tados por los sistemas operativos de Macintosh proporcionan un interesante caso de estudio: his tóricamente, Mac OS no proporcionaba una interfaz de línea de comandos, siendo obligatorio que los usuarios interactuaran con el sistema operativo a través de la interfaz GUI; sin embargo, con el lanzamiento de Mac OS X (que está parcialmente basado en un kernel UNIX), el sistema operativo proporciona ahora tanto la nueva interfaz Aqua, como una interfaz de línea de comandos. La interfaz de usuario puede variar de un sistema a otro e incluso de un usuario a otro dentro de un sistema; por esto, la interfaz de usuario se suele, normalmente, eliminar de la propia estruc 2.3 Llamadas al sistema 39 tura del sistema. El diseño de una interfaz de usuario útil y amigable no es, por tanto, una función directa del sistema operativo. En este libro, vamos a concentrarnos en los problemas fundamen tales de proporcionar un servicio adecuado a los programas de usuario. Desde el punto de vista del sistema operativo, no diferenciaremos entre programas de usuario y programas del sistema. Llamadas al sistema Las llam adas al sistem a proporcionan una interfaz con la que poder invocar los servicios que el sistema operativo ofrece. Estas llamadas, generalmente, están disponibles como rutinas escritas en C y C++, aunque determinadas tareas de bajo nivel, como por ejemplo aquéllas en las que se tiene que acceder directamente al hardware, pueden necesitar escribirse con instrucciones de lenguaje ensamblador. Antes de ver cómo pone un sistema operativo a nuestra disposición las llamadas al sistema, vamos a ver un ejemplo para ilustrar cómo se usan esas llamadas: suponga que deseamos escri bir un programa sencillo para leer datos de un archivo y copiarlos en otro archivo. El primer dato de entrada que el programa va a necesitar son los nombres de los dos archivos, el de entrada y el de salida. Estos nombres pueden especificarse de muchas maneras, dependiendo del diseño del sistema operativo; un método consiste en que el programa pida al usuario que introduzca los nombres de los dos archivos. En un sistema interactivo, este método requerirá una secuencia de llamadas al sistema: primero hay que escribir un mensaje en el indicativo de comandos de la pan talla y luego leer del teclado los caracteres que especifican los dos archivos. En los sistemas basa dos en iconos y en el uso de un ratón, habitualmente se suele presentar un menú de nombres de archivo en una ventana. El usuario puede entonces usar el ratón para seleccionar el nombre del archivo de origen y puede abrirse otra ventana para especificar el nombre del archivo de des tino. Esta secuencia requiere realizar numerosas llamadas al sistema de E/S. Una vez que se han obtenido los nombres de los dos archivos, el programa debe abrir el archi vo de entrada y crear el archivo de salida. Cada una de estas operaciones requiere otra llamada al sistema. Asimismo, para cada operación, existen posibles condiciones de error. Cuando el progra ma intenta abrir el archivo de entrada, puede encontrarse con que no existe ningún archivo con ese nombre o que está protegido contra accesos. En estos casos, el programa debe escribir un men saje en la consola (otra secuencia de llamadas al sistema) y terminar de forma anormal (otra lla mada al sistema). Si el archivo de entrada existe, entonces se debe crear un nuevo archivo de salida. En este caso, podemos encontrarnos con que ya existe un archivo de salida con el mismo nombre; esta situación puede hacer que el programa termine (una llamada al sistema) o podemos borrar el archivo existente (otra llamada al sistema) y crear otro (otra llamada más). En un siste ma interactivo, otra posibilidad sería preguntar al usuario (a través de una secuencia de llamadas al sistema para mostrar mensajes en el indicativo de comandos y leer las respuestas desde el ter minal) si desea reemplazar el archivo existente o terminar el programa. Una vez que ambos archivos están definidos, hay que ejecutar un bucle que lea del archivo de entrada (una llamada al sistema; y escriba en ei archivo de salida (otra llamada al sistema). Cada lectura y escritura debe devolver información de estado relativa a las distintas condiciones posi bles de error. En la entrada, el programa puede encontrarse con que ha llegado al final del archi vo o con que se ha producido un fallo de hardware en la lectura (como por ejemplo, un error de paridad). En la operación de escritura pueden producirse varios errores, dependiendo del dispo sitivo de salida (espacio de disco insuficiente, la impresora no tiene papel, etc.) Finalmente, después de que se ha copiado el archivo completo, el programa cierra ambos archi vos (otra llamada al sistema), escribe un mensaje en la consola o ventana (más llamadas al siste ma) y, por último, termina normalmente (la última llamada al sistema). Como puede ver, incluso los programas más sencillos pueden hacer un uso intensivo del sistema operativo. Frecuentemen te, ¡os sistemas ejecutan miles d e Mamadas al sistema por segundo. Esta secuencia de llamadas al sistema se muestra en la Figura 2.1. Sin embargo, la mayoría de los programadores no ven este nivel de detalle. Normalmente, los desarroliadores de aplicaciones diseñan sus programas utilizando una API (application program- Capítulo 2 Estructuras de sistemas operativos archivo de destino — enoada llamada t - frentrada ̂ <■ ■' 3jj™ S a A fe del aiphivo de salida'} Éscnotc&ídicaEvo’de comandoser» " £'“iL »J¿ airada fe'entradá' _____ _ eí abortar * >í!’ CiÉall^j^íJ&Salida' }' -v-, *;* si et archivo existe, abortar Bucli ■jBawsí»-»- G e T S S r a S r f é entrada" ’ ' JílV* Iaun mensa,e de ternur « «gflfeSaáir Figura 2.1 Ejemplo de utilización de las llamadas al sistema. ming interface, interfaz de programación de aplicaciones). La API especifica un conjunto de fun ciones que el programador de aplicaciones puede usar, indicándose los parámetros que hay que pasar a cada función y los valores de retom o que el programador debe esperar. Tres de las API disponibles para programadores de aplicaciones son la API Win32 para sistemas Windows, la API POSIX para sistemas basados en POSIX (queincluye prácticamente todas las versiones de UNIX, Linux y Mac OS X) y la API Java para diseñar programas que se ejecuten sobre una máquina vir tual de Java. Observe que los nombres de las llamadas al sistema que usamos a lo largo del texto son ejem plos genéricos. Cada sistema operativo tiene sus propios nombres de llamadas al sistema. Entre bastidores, las funciones que conforman una API invocan, habitualmente, a las llamadas al sistema por cuenta del programador de la aplicación. Por ejemplo, la función Creace- Process () de W in32 (que, como su propio nombre indica, se emplea para crear un nuevo pro ceso) lo que hace, realmente, es invocar la llamada al sistema NTCreateProcess ( ) del kernel de Windows. ¿Por qué un programador de aplicaciones preferiría usar una API en lugar de invocar las propias llamadas al sistema? Existen varias razones para que sea así. Una ventaja de progra mar usando una API está relacionada con la portabilidad: un programador de aplicaciones diseña un programa usando una API cuando quiere poder compilar y ejecutar su programa en cualquier sistema que soporte la misma API (aunque, en la práctica, a menudo existen diferencias de arqui tectura que hacen que esto sea más difícil de lo que parece). Además, a menudo resulta más difí cil trabajar con las propias llamadas al sistema y exige un grado mayor de detalle que usar las APi que los programadores de aplicaciones tienen a su disposición. De todos modos, existe una fuer te correlación entre invocar una función de la API y su llamada al sistema asociada disponible en el kernel. De hecho, muchas de las API Win32 y POSIX son similares a las llamadas al sistema nati vas proporcionadas por los sistemas operativos UNIX, Linux y Windows. El sistema de soporte en tiempo de ejecución (un conjunto de funciones de biblioteca que suele incluirse con los compiladores) de la mayoría de los lenguajes de programación proporciona una interfaz de llamadas al sistema que sirve como enlace con las llamadas al sistema disponibles en el sistema operativo. La interfaz de llamadas al sistema intercepta las llamadas a función dentro de las API e invoca la llamada al sistema necesaria. Habitualmente, cada llamada al sistema tiene asociado un número y la interfaz de llamadas al sistema mantiene una tabla indexada según dichos números. Usando esa tabla, la interfaz de llamadas al sistema invoca la llamada necesaria del kernel del sistema operativo y devuelve el estado de la ejecución de la llamada al sistema y los posibles valores de retorno. 2.3 Llamadas al sistema 41 . ^EJEM PLO. DEAPI ESTÁNDAR .■«A -*-* Como ejem plo de API estándar, consí3^re|a función H e a d F ile () de la API W in32, unafunA d on gufeJLeeJdatog.de.un cúrchiv.o^EnL^ E Íg g ra 22 se m uestra la API correspondiente a„esta',\~ '«W v?; valor ( "T. y;* de retorno ReadE (HANDLE LPVOED DWORD LPDWORD LPOVERLAPPED o v l ) file, b u f f e r , bytes To Reac bytes Read, nombre de función •" -* > * •i * * . * * * * ' t? >■' ' * - * ' 2 .2 ? * Á F ^ V r a función ReadfileO parámetros J^ o s ^ a rá m e tro s de,R« .V*wfW£c*J * i*¿zZAülT-T TTMSrtí Ĵlf * Í tiitk *■ Ŝ -c-jíe?* J H*t «ÍL * */V* 5 .t- w .« >■»*• I,*»* _i I ii ■ mi ■IM|I , I huuji, ..... '**!■'-£• num erw d& b^eyrado^duranteJa ultim a lectura. ~- * *Í V i A ' V **# <-* fT'fc - «V'ittmWv-r *.* ■r' -*V * w * * * •'■ V”- ^ P E E D ^ f^ fp r. igdica sisfeestá üsand^g/g solapada.. ' . . . . . , (r _ Quien realiza la llamada no tiene por qué saber nada acerca de cómo se implementa dicha lla mada al sistema o qué es lo que ocurre durante la ejecución. Tan sólo necesita ajustarse a lo que la API especifica y entender lo que hará el sistema operativo como resultado de la ejecución de dicha llamada al sistema. Por tanto, la API oculta al programador la mayor parte de los detalles de la interfaz del sistema operativo, los cuales son gestionados por la biblioteca de soporte en tiem po de ejecución. Las relaciones entre una API, la interfaz de llamadas al sistema y el sistema ope rativo se muestran en la Figura 2.3, que ilustra cómo gestiona el sistema operativo una aplicación de usuario invocando la llamada al sistema open (). Las llamadas al sistema se llevan a cabo de diferentes formas, dependiendo de la com putado ra que se utilice. A menudo, se requiere más información que simplemente la identidad de la lla mada al sistema deseada. El tipo exacto y la cantidad de información necesaria varían según el sistema operativo y la llamada concreta que se efectúe. Por ejemplo, para obtener un dato de entrada, podemos tener que especificar el archivo o dispositivo que hay que utilizar como origen, así como la dirección y la longitud del búfer de memoria en el que debe almacenarse dicho dato de entrada. Por supuesto, el dispositivo o archivo y la longitud pueden estar implícitos en la lla mada. Para pasar parámetros al sistema operativo se emplean tres métodos generales. El más senci llo de ellos consiste en pasar los parámetros en una serie de registros. Sin embargo, en algunos casos, puede haber más parámetros que registros disponibles. En estos casos, generalmente, los parámetros se almacenan en un bloque o tabla, en memoria, y la dirección del bloque se pasa como parámetro en un registro (Figura 2.4). Éste es el método que utilizan Linux y Solaris. El programa también puede colocar, o insertar, los parámetros en la pila y el sistema operativo se encargará de extraer de la pila esos parámetros. Algunos sistemas operativos pretieren el método del bloque o el de la pila, púrque no limitan el número o la longitud de los parámetros que se quieren pasar. 42 Capítulo 2 Estructuras de sistemas operativos kernel Implementación de la llamada al sistema open (; return ------------------- F igura 2.3 Gestión de la invocación de la llamada al sistema openQ por parte de una aplicación de usuario. cargar v-;*direcc¡óo-X -« * llamada al ■ sistema 13 programa de usuario registro usar parámetros de tabla X ► 4** í » ■ * ' ..-i ' "- ... sistema operativo código para la r llamada al J sistema 13 Figura 2.4 Paso de parámetros como tabla. 2.4 Tipos de llamadas al sistema Las llamadas al sistema pueden agruparse de forma muy general en cinco categorías principales control de procesos, m anipulación de archivos, m anipulación de dispositivos, m antenim ienh de inform ación y com unicaciones. En las Secciones 2.4.1 a 2.4.5, expondremos brevemente lo tipos de llamadas al sistema que un sistema operativo puede proporcionar. La mayor parte d estas llamadas al sistema soportan, o son soportadas por, conceptos y funciones que se explica: en capítulos posteriores. La Figura 2.5 resume los. tipos de llamadas al sistema que normalment proporciona un sistema operativo. 2.4.1 Control de procesos Un programa en ejecución necesita poder interrumpir dicha ejecución bien de forma normal (ene o de forma anormal (a b e re ) . Si se hace una llamada al sistema para terminar de forma anoriru el programa actualmente en ejecución, o si el programa tiene un problema y da lugar a una excei ción de error, en ocasiones se produce un volcado de memoria v se genera un mensaje de erro1 2.4 Tipos de llamadas al sistema 43 • Control de procesos o terminar, abortar o cargar, ejecutar o crear procesos, terminar procesos o obtener atributos del proceso, definir atributos del proceso o esperar para obtener tiempo o esperar suceso, señalizar suceso o asignar y liberar memoria • Administración de archivos o crear archivos, borrar archivos o abrir, cerrar o leer, escribir, reposicionar o obtener atributos de archivo, definir atributos de archivo • Administración de dispositivos o solicitar dispositivo, liberar dispositivo o leer, escribir, reposicionar o obtener atributos de dispositivo, definir atributos de dispositivo o conectar y desconectar dispositivos lógicamente • Mantenimiento de información o obtener la hora o la fecha, definir la horao la fecha o obtener datos del sistema, establecer datos del sistema o obtener los atributos de procesos, archivos o dispositivos o establecer los atributos de procesos, archivos o dispositivos • Comunicaciones o crear, eliminar conexiones de comunicación - o enviar, recibir mensajes o transferir información de estado o conectar y desconectar dispositivos remotos Figura 2.5 Tipos de llamadas al sistema. La información de volcado se escribe en disco y un depurador (un programa del sistema diseña do para ayudar al programador a encontrar y corregir errores) puede examinar esa información de volcado con el fin de determinar la causa del problema. En cualquier caso, tanto en las circuns tancia normales como en las anormales, el sistema operativo debe transferir el control al intérpre te de comandos que realizó la invocación del programa; el intérprete leerá entonces el siguiente comando. En un sistema interactivo, el intérprete de comandos simplemente continuará con el siguiente comando, dándose p o r supuesto que el usuario ejecutará un comando adecuado para responder a cualquier error. En un sistema GUI, una ventana emergente alertará al usuario del error y le pedirá que indique lo que hay que hacer. En un sistema de procesamiento por lotes, el intérprete de comandos usualmente dará por terminado todo el trabajo de procesamiento v con- Capítulo 2 Estructuras de sistemas operativos tinuará con el siguiente trabajo. Algunos sistemas permiten utilizar tarjetas de control para indi car acciones especiales de recuperación en caso de que se produzcan errores. Una tarjeta de con trol es un concepto extraído de los sistemas de procesamiento por lotes: se trata de un comando que permite gestionar la ejecución de un proceso. Si el programa descubre un error en sus datos de entrada y decide terminar anormalmente, también puede definir un nivel de error; cuanto más severo sea el error experimentado, mayor nivel tendrá ese parámetro de error. Con este sistema, podemos combinar entonces la terminación normal y la anormal, definiendo una terminación nor mal como un error de nivel 0. El intérprete de comandos o el siguiente programa pueden usar el nivel de error para determinar automáticamente la siguiente acción que hay que llevar a cabo. Un proceso o trabajo que ejecute un programa puede querer cargar (load) y ejecutar (execu- te) otro programa. Esta característica permite al intérprete de comandos ejecutar un programa cuando se le solicite mediante, por ejemplo, un comando de usuario, el clic del ratón o un coman do de procesamiento por lotes. Una cuestión interesante es dónde devolver el control una vez que termine el programa invocado. Esta cuestión está relacionada con el problema de si el programa que realiza la invocación se pierde, se guarda o se le permite continuar la ejecución concurrente mente con el nuevo programa. Si el control vuelve al programa anterior cuando el nuevo programa termina, tenemos que guardar la imagen de memoria del programa existente; de este modo puede crearse un mecanis mo para que un programa llame a otro. Si ambos programas continúan concurrentemente, habre mos creado un nuevo trabajo o proceso que será necesario controlar mediante los mecanismos de 2,4 Tipos de llamadas al sistema 45 multiprogramación. Por supuesto, existe una llamada al sistema específica para este propósito, c r e a te p ro cess o submit job. Si creamos un nuevo trabajo o proceso, o incluso un conjunto de trabajos o procesos, también debemos poder controlar su ejecución. Este control requiere la capacidad de determinar y resta blecer los atributos de un trabajo o proceso, incluyendo la prioridad del trabajo, el tiempo máxi mo de ejecución permitido, etc.'(get’ p ro cess a t t r i b u t e s y s e t p ro cess a t tr ib u te s ) . También puede que necesitemos terminar un trabajo o proceso que hayamos creado (term ín a te p ro cess) si comprobamos que es incorrecto o decidimos que ya no es necesario. Una vez creados nuevos trabajos o procesos, es posible que tengamos que esperar a que termi nen de ejecutarse. Podemos esperar una determinada cantidad de tiempo (wait time) o, más probablemente, esperaremos a que se produzca un suceso específico (wait event). Los trabajos o procesos deben indicar cuándo se produce un suceso (sig n al event). En el Capítulo 6 se explican en detalle las llamadas al sistema de este tipo, las cuales se ocupan de la coordinación de procesos concurrentes. Existe otro conjunto de llamadas al sistema que resulta útil a la hora de depurar un programa. Muchos sistemas proporcionan llamadas al sistema para volcar la memoria (dump); esta funciona lidad resulta muy útil en las tareas de depuración. Aunque no todos los sistemas lo permitan, mediante un programa de traza (tra ce ) genera una lista de todas las instrucciones según se eje cutan. Incluso hay microprocesadores que proporcionan un modo de la CPU, conocido como modo paso a paso, en el que la CPU ejecuta una excepción después de cada instrucción. Normalmente, se usa un depurador para atrapar esa excepción. Muchos sistemas operativos proporcionan un perfil de tiempo de los programas para indicar la cantidad de tiempo que el programa invierte en una determinada instrucción o conjunto de ins trucciones. La generación de perfiles de tiempos requiere disponer de una funcionalidad de traza o de una serie de interrupciones periódicas del temporizador. Cada vez que se produce una inte rrupción del temporizador, se registra el valor del contador de programa. Con interrupciones del temporizador suficientemente frecuentes, puede obtenerse una imagen estadística del tiempo invertido en las distintas partes del programa. Son tantas las facetas y variaciones en el control de procesos y trabajos que a continuación vamos a ver dos ejemplos para clarificar estos conceptos; uno de ellos emplea un sistema mono- tarea y el otro, un sistema multitarea. El sistema operativo MS-DOS es un ejemplo de sistema monotarea. Tiene un intérprete de comandos que se invoca cuando se enciende la computadora [Figura 2.7(a)]. Dado que MS-DOS es un sistema que sólo puede ejecutar una tarea cada vez, utili za un método muy simple para ejecutar un programa y no crea ningún nuevo proceso: carga el programa en memoria, escribiendo sobre buena parte del propio sistema, con el fin de proporcio nar al programa la mayor cantidad posible de memoria [Figura 2.7(b)]. A continuación, establece- memoria libre memoria libre procesos kernel kernel (a) (b) Figura 2 .7 Ejecución de un programa en MS-DOS. (a) Al inicio del sistema, (b) Ejecución de un programa Capítulo 2 Estructuras de sistemas operativos el puntero de instrucción en la primera instrucción del programa y el programa se ejecuta. Eventualmente, se producirá un error que dé lugar a una excepción o, si no se produce ningún error, el programa ejecutará una llamada al sistema para terminar la ejecución. En ambos casos, el código de error se guarda en la memoria del sistema para su uso posterior. Después de esta secuencia de operaciones, la pequeña parte del intérprete de comandos que no se ha visto sobres crita reanuda la ejecución. La primera tarea consiste en volver a cargar el resto del intérprete de > comandos del disco; luego, el intérprete de comandos pone a disposición del usuario o del siguiente programa el código de error anterior. FreeBSD (derivado de Berkeley UNIX) es un ejemplo de sistema multitarea. Cuando un usua rio inicia la sesión en el sistema, se ejecuta la shell elegida por el usuario. Esta shell es similar a la shell de MS-DOS, en cuanto que acepta comandos y ejecuta los programas que el usuario solicita. Sin embargo, dado que FreeBSD es un sistema multitarea, el intérprete de comandos puede seguir ejecutándose mientras que se ejecuta otro programa (Figura 2.8). Para iniciar un nuevo proceso, la shell ejecuta la llamada f ork () al sistema. Luego, el programa seleccionado se carga en memoriamediante una llamada exec () al sistema y el programa se ejecuta. Dependiendo de la forma en que se haya ejecutado el comando, la shell espera a que el proceso termine o ejecuta el proceso “en segundo plano”. En este último caso, la shell solicita inmediatamente otro comando. Cuando un proceso se ejecuta en segundo plano, no puede recibir entradas directamente desde el teclado, ya que la shell está usando ese recurso. Por tanto, la E /S se hace a través de archivos o de una inter faz GUI. Mientras tanto, el usuario es libre de pedir a la shell que ejecute otros programas, que monitorice el progreso del proceso en ejecución, que cambie la prioridad de dicho programa, etc. Cuando el proceso concluye, ejecuta una llamada exit () al sistema para terminar, devolviendo al proceso que lo invocó un código de estado igual 0 (en caso de ejecución satisfactoria) o un códi go de error distinto de cero. Este código de estado o código de error queda entonces disponible para la shell o para otros programas. En el Capítulo 3 se explican los procesos, con un programa de ejemplo que usa las llamadas al sistema f ork () y exec (). 2.4.2 Administración de archivos En los Capítulos 10 y 11 analizaremos en detalle el sistema de archivos. De todos modos, pode mos aquí identificar diversas llamadas comunes al sistema que están relacionadas con la gestión de archivos. En primer lugar, necesitamos poder crear (create) y borrar (delere) archivos. Ambas llama das al sistema requieren que se proporcione el nombre del archivo y quizá algunos de los atribu tos del mismo. Una vez que el archivo se ha creado, necesitamos abrirlo (open) y utilizarlo. También tenemos que poder leerlo (read), escribir (v/rite) en él, o reposicionarnos (repos i - tion), es decir, volver a un punto anterior o saltar al final del archivo, por ejemplo. Por último, tenemos que poder cerrar ( c ió s e ) el archivo, indicando que ya no deseamos usarlo. proceso D memoria libre proceso C proceso B kernel F igura 2.8 FreeBSD ejecutando múltiples programas. 2.4 Tipos de llamadas al sistema 47 a c é r’q u ífjó s sistem as^ oj^ erath . t ’1' . *' ¿ -i'f' 4 T S lillS lS l FACILID AD;DE TRAZADO DINÁMICO DE SOLAfUSilO; ^ ^ .*'. v .v • _ ;r ^ prender, dé depúrar y deopijmi- ' , , iP’lá^vés^aaórv^’imipléBaapfe-í̂ - ciórt* de'séfémas' opéráti^^T^r'ejemplo; Solaris lO^mtluye^a^fu^ trazado ' • dinámico dt race. Esta füpcidñalidad affádé'din3ini«ffnfenteitina serié ¿¿¿ “son ias”rais^to- ma que se esté ejecutando: dichas sondas pueden consultarse mediante el lenguaje’-de pro- • gramaaóh-D:y proporcionan; üiTáíásombrosa>ígantidad'de-.información. sobre ..eCterne/,. el estado-13él’‘sístema y laéáhtividadesde los procesos. Por .ejemplo, la Figura 2.9 .muestra las ^^chw^d^dé^há^áj5Ifc^dhícuáh'd‘oí>s^!'éjécat3:ü na Uamada-ai sistema (i oct l)j¿muestra ■ ■ >■ S iX«» ¡w / J n n f r r t / 4 ñ l T r n k it/t/ n n r ‘l wn i n / » i < f ,a r 1 * l l a r T t l - terínSM^OT-K” en modo kemd, > - * ■ * :̂ ■ , í , ^ • r» j *uvi* »'■>«'. —____ _____ti ‘ISW teásssssM SW # ./all.d 'pgrep xclock' XEventsQueued dtrace: script ',/all.d' matched 52377 prc CPU FUNCTION 0 -> XEventsQueued U > _XEventsQueued U -> _XllTransBytesReadable U <- _XllTransBytesReadable U -> _XllTransSocketBytesReadable U <- XllTransSocketBytesreadable U « * *1 > -* V•* «\ ■tí?**?- ' t -_-S. ÍW A ^ r? r . ■ -> ioctl -> ioctl -> getf -> set_accive_fd <- set_active_fd <- getf -> get_udatamodel <- get_udatamodel -> releasef -> clear_active_fd <- clear_active_fd -> cv_brcadcast <- cv_brcadcast <- releasef - <- ioctl <- ioctl XEventsQueued U K K K K K K K J&P/X'-Í, j i t. ,.V». ’V! -. ■> >f — * r . -...i j¡5»V *, *é ¡ p ¡í ¡ ¡ ¡ í tea efeh iis***- Necesitamos también poder hacer estas operaciones con directorios, si disponemos de una estructura de directorios para organizar los archivos en el sistema de archivos. Además, para cual quier archivo o directorio, necesitamos poder determinar los valores de diversos atributos y, quizá, cambiarlos si fuera necesario. Los atributos de archivo incluyen el nombre del archivo, el tipo de archivo, los códigos de protección, la información de las cuentas de usuario, etc. Al menos Capítulo 2 Estructuras de sistemas operativos son necesarias dos llamadas al sistema (ge t file attribute y set file attribute) para cumplir esta función. Algunos sistemas operativos proporcionan muchas más llamadas, como por ejemplo llamadas para mover (move) y copiar (copy) archivos. Otros proporcionan una API que realiza dichas operaciones usando código software y otras llamadas al sistema, y otros incluso suministran programas del sistema para llevar a cabo dichas tareas. Si los programas del sistema son invocables por otros programas, entonces cada uno de fellos puede ser considerado una API por los demás programas del sistema. 2.4.3 Adm inistración de dispositivos Un proceso puede necesitar varios recursos para ejecutarse: memoria principal, unidades de disco, acceso a archivos, etc. Si los recursos están disponibles, pueden ser concedidos y el control puede devolverse al proceso de usuario. En caso contrario, el proceso tendrá que esperar hasta que haya suficientes recursos disponibles. Puede pensarse en los distintos recursos controlados por el sistema operativo como si fueran dispositivos. Algunos de esos dispositivos son dispositivos físicos (por ejemplo, cintas), mientras que en otros puede pensarse como en dispositivos virtuales o abstractos (por ejemplo, archivos). Si hay varios usuarios en el sistema, éste puede requerirnos primero que solicitemos (request) el dispositivo, con el fin de aseguramos el uso exclusivo del mismo. Una vez que hayamos termi nado con el dispositivo, lo liberaremos (release). Estas funciones son similares a las llamadas al sistema para abrir (open) y cerrar (cióse) archivos. Otros sistemas operativos permiten un acce so no administrado a los dispositivos. El riesgo es, entonces, la potencial contienda por el uso de los dispositivos, con el consiguiente riesgo de que se produzcan interbloqueos; este tema se des cribe en el Capítulo 7. Una vez solicitado el dispositivo (y una vez que se nos haya asignado), podemos leer (read), escribir, (write) y reposicionar (reposition) el dispositivo, al igual que con los archivos. De hecho, la similitud entre los dispositivos de E/S y los archivos es tan grande que muchos sis temas operativos, incluyendo UNIX, mezclan ambos en una estructura combinada de archivo- dispositivo. Algunas veces, los dispositivos de E /S se identifican mediante nombres de archivo, ubicaciones de directorio o atributos de archivo especiales. La interfaz de usuario también puede hacer que los archivos y dispositivos parezcan similares, incluso aunque las llamadas al sistema subyacentes no lo sean. Este es otro ejemplo de las muchas decisiones de diseño que hay que tomar en la creación de un sistema operativo y de una interfaz de usuario. 2.4.4 Mantenim iento de información Muchas llamadas al sistema existen simplemente con el propósito de transferir información entre el programa de usuario y el sistema operativo. Por ejemplo, la mayoría de los sistemas ofrecen una llamada al sistema para devolver la hora (time) y la fecha (date) actuales. Otras llamadas al sis tema pueden devolver información sobre el sistema, como por ejemplo el número actual de usua rios, el número de versión del sistema operativo, la cantidad de memoria libre o de espacio en disco, etc. Además, el sistema operativo mantiene información sobre todos sus procesos, y se usan llama das al sistema para acceder a esa información. Generalmente, también se usan llamadas para configurar la inform ación de los procesos (get process attributes y set process attributes). En la Sección 3.1.3 veremos qué información se mantiene habitualmente acerca de los procesos. 2.4.5 Comunicaciones Existen dos modelos comunes de comunicación interprocesos: el modelo de paso de mensajesy el modelo de memoria compartida. En el m odelo de paso de m ensajes, los procesos que se comu nican intercambian mensajes entre sí para transferirse información. Los mensajes se pueden inter 2.5 Programas del sistema 49 cambiar entre los procesos directa o indirectamente a través de un buzón de correo común. Antes de que la comunicación tenga lugar, debe abrirse una conexión. Debe conocerse de antemano el nombre del otro comunicador, ya sea otro proceso del mismo sistema o un proceso de otra com putadora que esté conectada a través de la red de comunicaciones. Cada computadora de una red tiene un nombre de host, por el que habitualmente se la conoce. Un host también tiene un identifi- cador de red, como por ejemplo una dirección IP. De forma similar, cada proceso tiene un nombre de proceso, y este nombre se traduce en un identificador mediante el cual el sistema operativo puede hacer referencia al proceso. Las llamadas al sistema g e t host id y g e t p ro ce ssid rea lizan esta traducción. Los identificadores se pueden pasar entonces a las llamadas de propósito general open y c ió se proporcionadas por el sistema de archivos o a las llamadas específicas al sistema open con n ection y c ió s e conn ection , dependiendo del modelo de comunicación del sistema. Usualmente, el proceso receptor debe conceder permiso para que la comunicación tenga lugar, con una llamada de aceptación de la conexión (accep t connection). La mayoría de los procesos que reciben conexiones son de propósito especial; dichos procesos especiales se denominan demonios y son programas del sistema que se suministran específicamente para dicho propósito. Los procesos demonio ejecutan una llamada w ait fo r con n ection y despiertan cuando se establece una conexión. El origen de la comunicación, denominado cliente, y el demo nio receptor, denominado servidor, intercambian entonces mensajes usando las llamadas al siste ma para leer (read message) y escribir (w rite message) mensajes. La llamada para cerrar la conexión (c ió se conn ection ) termina la comunicación. En el m odelo de m em oria com partida, los procesos usan las llamada al sistema shared memory c r e a te y s h a r e d memo ry attach p aracreary obtener acceso a regiones de la memo ria que son propiedad de otros procesos. Recuerde que, normalmente, el sistema operativo inten ta evitar que un proceso acceda a la memoria de otro proceso. La memoria compartida requiere que dos o más procesos acuerden eliminar esta restricción; entonces pueden intercambiar infor mación leyendo y escribiendo datos en áreas de la memoria compartida. La forma de los datos y su ubicación son determinadas por parte de los procesos y no están bajo el control del sistema ope rativo. Los procesos también son responsables de asegurar que no escriban simultáneamente en las mismas posiciones. Tales mecanismos se estudian en el Capítulo 6. En el Capítulo 4, veremos una variante del esquema de procesos (lo que se denomina “hebras de ejecución”) en la que se comparte la memoria de manera predeterminada. Los dos modelos mencionados son habituales en los sistemas operativos y la mayoría de los sistemas implementan ambos. El modelo de paso de mensajes resulta útil para intercambiar can tidades pequeñas de datos, dado que no hay posibilidad de que se produzcan conflictos; también es más fácil de implementar que. el modelo de memoria compartida para la comunicación inter- procesos. La memoria compartida permite efectuar la comunicación con una velocidad máxima y con la mayor comodidad, dado que puede realizarse a velocidades de memoria cuando tiene lugar dentro de una misma computadora. Sin embargo, plantea problemas en lo relativo a la pro tección y sincronización entre los procesos que comparten la memoria. Programas del sistema Otro aspecto fundamental de los sistemas modernos es la colección de programas del sistema. Recuerde la Figura 1.1, que describía la jerarquía lógica de una computadora: en el nivel inferior está el hardware; a continuación se encuentra el sistema operativo, luego los programas del siste ma y, finalmente, los programas de aplicaciones. Los programas del sistema proporcionan un cómodo entorno para desarrollar y ejecutar programas. Algunos de ellos son, simplemente, inter faces de usuario para las llamadas al sistema; otros son considerablemente más complejos. Pueden dividirse en las siguientes categorías: • Administración de archivos. Estos programas crean, borran, copian, cambian de nombre, imprimen, vuelcan, listan y. de forma general, manipulan archivos y directorios. • Información de estado. Algunos programas simplemente solicitan a! sistema la fecha, la hora, la cantidad de memoria o de espacio de disco disponible, el número de usuarios o 50 Capítulo 2 Estructuras de sistemas operativos información de estado similar. Otros son más complejos y proporcionan información deta-: liada sobre el rendimiento, los inicios de sesión y los mecanismos de depuración. Normalmente, estos programas formatean los datos de salida y los envían al terminal o a otros dispositivos o archivos de salida, o presentan esos datos en una ventana de la interfaz GUI. Algunos sistemas también soportan un registro, que se usa para almacenar y recupe rar información de configuración. • Modificación de archivos. Puede disponerse de varios editores de texto para crear y modi ficar el contenido de los archivos almacenados en el disco o en otros dispositivos de alma cenamiento. También puede haber comandos especiales para explorar el contenido de los archivos en busca de un determinado dato o para realizar cambios en el texto. • Soporte de lenguajes de programación. Con frecuencia, con el sistema operativo se pro porcionan al usuario compiladores, ensambladores, depuradores e intérpretes para los len guajes de programación habituales, como por ejemplo, C, C++, Java, Visual Basic y PERL. • Carga y ejecución de programas. Una vez que el programa se ha ensamblado o compilado, debe cargarse en memoria para poder ejecutarlo. El sistema puede proporcionar cargadores absolutos, cargadores reubicables, editores de montaje y cargadores de sustitución. Tam bién son necesarios sistemas de depuración para lenguajes de alto nivel o para lenguaje máquina. • Comunicaciones. Estos programas proporcionan los mecanismos para crear conexiones vir tuales entre procesos, usuarios y computadoras. Permiten a los usuarios enviar mensajes a las pantallas de otros, explorar páginas web, enviar mensajes de correo electrónico, iniciar una sesión de forma remota o transferir archivos de una máquina a otra. Además de con los programas del sistema, la mayoría de los sistemas operativos se suminis tran con programas de utilidad para resolver problemas comunes o realizar operaciones fre cuentes. Tales programas son, por ejemplo, exploradores web, procesadores y editores de texto, hojas de cálculo, sistemas de bases de datos, compiladores, paquetes gráficos y de análisis esta dístico y juegos. Estos programas se conocen como utilidades del sistema o programas de apli cación. Lo que ven del sistema operativo la mayoría de los usuarios está definido por los programas del sistema y de aplicación, en lugar de por las propias llamadas al sistema. Consideremos, por ejemplo, los PC: cuando su computadora ejecuta el sistema operativo Mac OS X, un usuario puede ver la GUI, controlable mediante un ratón y caracterizada por una interfaz de ventanas. Alternativamente (o incluso en una de las ventanas) el usuario puede disponer de una shdl de UNIX que puede usar como línea de comandos. Ambos tipos de interfaz usan el mismo conjunto de llamadas al sistema, pero las llamadas parecen diferentes y actúan de forma diferente. 2.6 Diseño e ¡mplementación del sistema operativo En esta sección veremos los problemas a los que nos enfrentamos al diseñar e implementar un sis tema operativo. Por supuesto, no existen soluciones completas y únicas a tales problemas,pero si podemos indicar una serie de métodos que han demostrado con el tiempo ser adecuados. 2.6.1 Objetivos del diseño El primer problema al diseñar un sistema es el de definir los objetivos y especificaciones. En el nivel más alto, el diseño del sistema se verá afectado por la elección del hardware y el tipo de sis tema: de procesamiento por lotes, de tiempo compartido, monousuario, multiusuario, distribui do, en tiempo real o de propósito general. Más allá de este nivel superior de diseño, puede ser complicado especificar los requisitos. Sin embargo, éstos se pueden dividir en dos grupos básicos: objetivos del usuario y objetivos del sis tema. 2.6 Diseño e implementación del sistema operativo 51 Los usuarios desean ciertas propiedades obvias en un sistema: el sistema debe ser cómodo de utilizar, fácil de aprender y de usar, fiable, seguro y rápido. Por supuesto, estas especificaciones no son particularmente útiles para el diseño del sistema, ya que no existe un acuerdo general sobre cómo llevarlas a la práctica. Un conjunto de requisitos similar puede ser definido por aquellas personas que tienen que diseñar, crear, mantener y operar el sistema. El sistema debería ser fácil de diseñar, implementar y mantener; debería ser flexible, fiable, libre de errores y eficiente. De nuevo, estos requisitos son vagos y pueden interpretarse de diversas formas. En resumen, no existe una solución única para el problema de definir los requisitos de un sis tema operativo. El amplio rango de sistemas que existen muestra que los diferentes requisitos pueden dar lugar a una gran variedad de soluciones para diferentes entornos. Por ejemplo, los requisitos para VxWorks, un sistema operativo en tiempo real para sistemas integrados, tienen que ser sustancialmente diferentes de los requisitos de M VS, un sistema operativo multiacceso y multiusuario para los mainframes de IBM. Especificar y diseñar un sistema operativo es una tarea extremadamente creativa. Aunque ningún libro de texto puede decirle cómo hacerlo, se ha desarrollado una serie de princi pios generales en el campo de la in gen iería del softw are, algunos de los cuales vamos a ver ahora. 2.6.2 Mecanismos y políticas Un principio importante es el de separar las políticas de los m ecanism os. Los mecanismos determinan cómo hacer algo; las políticas determinan qué hacer. Por ejemplo, el temporizador (véase la Sección 1.5.2) es un mecanismo para asegurar la protección de la CPU, pero la decisión de cuáles deben ser los datos de temporización para un usuario concreto es una decisión de polí tica. La separación de políticas y mecanismos es importante por cuestiones de flexibilidad. Las polí ticas probablemente cambien de un sitio a otro o con el paso del tiempo. En el caso peor, cada cam bio en una política requerirá un cambio en el mecanismo subyacente; sería, por tanto, deseable un mecanismo general insensible a los cambios de política. Un cambio de política requeriría entonces la redefinición de sólo determinados parámetros del sistema. Por ejemplo, considere un mecanis mo para dar prioridad a ciertos tipos de programas: si el mecanismo está apropiadamente sepa rado de la política, puede utilizarse para dar soporte a una decisión política que establezca que los programas que hacen un uso intensivo de la E/S tengan prioridad sobre los que hacen un uso intensivo de la CPU, o para dar soporte a la política contraria. Los sistemas operativos basados en microkernel (Sección 2.7.3) llevan al extremo la separación de mecanismos y políticas, implementando un conjunto básico de bloques componentes primiti vos. Estos bloques son prácticamente independientes de las políticas concretas, permitiendo que se añadan políticas y mecanismos más avanzados a través de módulos del kemel creados por el usuario o a través de los propios programas de usuario. Por ejemplo, considere la historia de UNIX: al principio, disponía de un planificador de tiempo compartido, mientras que en la versión más reciente de Solaris la planificación se controla mediante una serie de tablas cargables. Dependiendo de la tabla cargada actualmente, el sistema puede ser de tiempo compartido, de pro cesamiento por lotes, de tiempo real, de compartición equitativa, o cualquier combinación de los mecanismos anteriores. Utilizar un mecanismo de planificación de propósito general permite hacer muchos cambios de política con un único comando, lo ad -n ew -tab ie . En el otro extremo se encuentra un sistema como Windows, en el que tanto mecanismos como políticas se codifican en el sistema para forzar un estilo y aspecto globales. Todas las aplicaciones tienen interfaces simi lares, dado que la propia interfaz está definida en el kernel y en las bibliotecas del sistema. El sis tema operativo Mac OS X presenta una funcionalidad similar. Las decisiones sobre políticas son importantes para la asignación de recursos. Cuando es nece sario decidir si un recurso se asigna o no, se debe tomar una decisión política. Cuando la pregun ta es cómo en lugar de qué, es un mecanismo lo que hay que determinar. 52 Capítulo 2 Estructuras de sistemas operativos 2.7 2.6.3 Implementación Una vez que se ha diseñado el sistema operativo, debe implementarse. Tradicionalmente, los sis temas operativos tenían que escribirse en lenguaje ensamblador. Sin embargo, ahora se escriben en lenguajes de alto nivel como C o C++. El primer sistema que no fue escrito en lenguaje ensamblador fue probablemente el MCP (Master Control Program) para las computadoras Burroughs; MCP fue escrito en una variante de ALGOL. MULTICS, desarrollado en el MIT, fue escrito principalmente en P L /1 . Los sistemas opera tivos Linux y W indows XP están escritos en su mayor parte en C, aunque hay algunas pequeñas secciones de código ensamblador para controladores de dispositivos y para guardar y restaurar el estado de registros. Las ventajas de usar un lenguaje de alto nivel, o al menos un lenguaje de implementación de sistemas, para implementar sistemas operativos son las mismas que las que se obtiene cuando el lenguaje se usa para programar aplicaciones: el código puede escribirse más rápido, es más com pacto y más fácil de entender y depurar. Además, cada mejora en la tecnología de compiladores permitirá mejorar el código generado para el sistema operativo completo, mediante una simple recompilación. Por último, un sistema operativo es más fácil de portar (trasladar a algún otro hard ware) si está escrito en un lenguaje de alto nivel. Por ejemplo, MS-DOS se escribió en el lenguaje ensamblador 8088 de Intel; en consecuencia, está disponible sólo para la familia Intel de procesa dores. Por contraste, el sistema operativo Linux está escrito principalmente en C y está disponible para una serie de CPU diferentes, incluyendo Intel 80X86, Motorola 680X0, SPARC y MIPS RX000. Las únicas posibles desventajas de implementar un sistema operativo en un lenguaje de alto nivel se reducen a los requisitos de velocidad y de espacio de almacenamiento. Sin embargo, éste no es un problema importante en los sistemas de hoy en día. Aunque un experto programador en lenguaje ensamblador puede generar rutinas eficientes de pequeño tamaño, si lo que queremos es desarrollar programas grandes, un compilador moderno puede realizar análisis complejos y apli car optimizaciones avanzadas que produzcan un código excelente. Los procesadores modernos tienen una pipeline profunda y múltiples unidades funcionales que pueden gestionar dependen cias complejas, las cuales pueden desbordar la limitada capacidad de la mente humana para con trolar los detalles. Al igual que sucede con otros sistemas, las principales mejoras de rendimiento en los sistemas operativos son, muy probablemente, el resultado de utilizar mejores estructuras de datos y mejo res algoritmos, más que de usar un código optimizado en lenguaje ensamblador. Además, aun que los sistemas operativos tienen un gran tamaño, sólo una pequeña parte delcódigo resulta crítica para conseguir un alto rendimiento; el gestor de memoria y el planificador de la CPU son probablemente las rutinas más críticas. Después de escribir el sistema y de que éste esté funcio nando correctamente, pueden identificarse las rutinas que constituyan un cuello de botella y reemplazarse por equivalentes en lenguaje ensamblador. Para identificar los cuellos de botella, debemos poder monitorizar el rendimiento del sistema. Debe añadirse código para calcular y visualizar medidas del comportamiento del sistema. Hay diversas plataformas en las que el sistema operativo realiza esta tarea, generando trazas que pro porcionan información sobre el comportamiento del sistema. Todos los sucesos interesantes se registran, junto con la hora y los parámetros importantes, y se escriben en un archivo. Después, un programa de análisis puede procesar el archivo de registro para determinar el rendimiento del sistema e identificar los cuellos de botella y las ineficiencias. Estas mismas trazas pueden propor cionarse como entrada para una simulación que trate de verificar si resulta adecuado introducir determinadas mejoras. Las trazas también pueden ayudar a los desarrolladores a encontrar erro res en el comportamiento del sistema operativo. Estructura del sistema operativo La ingeniería de un sistema tan grande y complejo como un sistema operativo moderno debe hacerse cuidadosamente para que el sistema funcione apropiadamente y pueda modificarse con facilidad. Un método habitual consiste en dividir la tarea en componentés más pequeños, en lugar 2.7 Estructura del sistema operativo 53 de tener un sistema monolítico. Cada uno de estos módulos debe ser una parte bien definida del sistema, con entradas, salidas y funciones cuidadosamente especificadas. Ya hemos visto breve mente en el Capítulo 1 cuáles son los componentes más comunes de los sistemas operativos. En esta sección, veremos cómo estos componentes se interconectan y funden en un kernel. 2.7.1 Estructura simple Muchos sistemas comerciales no tienen una estructura bien definida. Frecuentemente, tales siste mas operativos comienzan siendo sistemas pequeños, simples y limitados y luego crecen más allá de su ámbito original; MS-DOS es un ejemplo de un sistema así. Originalmente, fue diseñado e implementado por unas pocas personas que no tenían ni idea de que iba a terminar siendo tan popular. Fue escrito para proporcionar la máxima funcionalidad en el menor espacio posible, por lo que no fue dividido en módulos de forma cuidadosa. La Figura 2.10 muestra su estructura. En MS-DOS, las interfaces y niveles de funcionalidad no están separados. Por ejemplo, los pro gramas de aplicación pueden acceder a las rutinas básicas de E /S para escribir directamente en la pantalla y las unidades de disco. Tal libertad hace que MS-DOS sea vulnerable a programas erró neos (o maliciosos), lo que hace que el sistema completo falle cuando los programas de usuario fallan. Como el 8088 de Intel para el que fue escrito no proporciona un modo dual ni protección hardware, los diseñadores de MS-DOS no tuvieron más opción que dejar accesible el hardware base. Otro ejemplo de estructuración limitada es el sistema operativo UNIX original. UNIX es otro sis tema que inicialmente estaba limitado por la funcionalidad hardware. Consta de dos partes sepa radas: el kernel y los programas del sistema. El kernel se divide en una serie de interfaces y controladores de dispositivo, que se han ido añadiendo y ampliando a lo largo de los años, a medida que UNIX ha ido evolucionando. Podemos ver el tradicional sistema operativo UNIX como una estructura de niveles, ilustrada en la Figura 2.11. Todo lo que está por debajo de la interfaz de llamadas al sistema y por encima del hardware físico es el kernel. El kernel proporciona el sistema de archivos, los mecanismos de planificación de la CPU, la funcionalidad de gestión de memoria y otras funciones del sistema operativo, a través de las llamadas al sistema. En resumen, es una enorme cantidad de funcionalidad que se combina en un sólo nivel. Esta estructura monolítica era difícil de implementar y de mantener. 2.7.2 Estructura en niveles Con el soporte hardware apropiado, los sistemas operativos puede dividirse en partes más peque ñas y más adecuadas que lo que permitían los sistemas originales MS-DOS o UNIX. El sistema ope rativo puede entonces mantener un control mucho mayor sobre la computadora y sobre las Figura 2.10 Estructura de niveles de MS-DOS. Capítulo 2 Estructuras de sistemas operativos 0)E ID Figura 2.11 Estructura del sistema UNIX. aplicaciones que hacen uso de dicha computadora. Los implementadores tienen más libertad para cambiar el funcionamiento interno del sistema y crear sistemas operativos modulares. Con el método de diseño arriba-abajo, se determinan las características y la funcionalidad globales y se separan en componentes. La ocultación de los detalles a ojos de los niveles superiores también es importante, dado que deja libres a los programadores para implementar las rutinas de bajo nivel como prefieran, siempre que la interfaz externa de la rutina permanezca invariable y la propia rutina realice la tarea anunciada'. Un sistema puede hacerse modular de muchas formas. Un posible método es mediante una estructura en niveles, en el que el sistema operativo se divide en una serie de capas (niveles). El nivel inferior (nivel 0) es el hardware; el nivel superior (nivel N) es la interfaz de usuario. Esta estructura de niveles se ilustra en la Figura 2.12. Un nivel de un sistema operativo es una imple- mentación de un objeto abstracto formado por una serie de datos y por las operaciones que per miten manipular dichos datos. Un nivel de un sistema operativo típico (por ejemplo, el nivel M) consta de estructuras de datos y de un conjunto de rutinas que los niveles superiores pueden invo car. A su vez, el nivel M puede invocar operaciones sobre los niveles inferiores. La principal ventaja del método de niveles es la simplicidad de construcción y depuración. Los niveles se seleccionan de modo que cada uno usa funciones (operaciones) y servicios de los nive les inferiores. Este método simplifica la depuración y la verificación del sistema. El primer nivel puede depurarse sin afectar al resto del sistema, dado que, por definición, sólo usa el hardware básico (que se supone correcto) para implementar sus funciones. Una vez que el primer nivel se ha depurado, puede suponerse correcto su funcionamiento mientras se depura el segundo nivel, etc. Si se encuentra un error durante la depuración de un determinado nivel, el error tendrá que estar localizado en dicho nivel, dado que los niveles inferiores a él ya se han depurado. Por tanto, el diseño e implementación del sistema se simplifican. Cada nivel se implementa utilizando sólo las operaciones proporcionadas por los niveles infe riores. Un nivel no necesita saber cómo se implementan dichas operaciones; sólo necesita saber qué hacen esas operaciones. Por tanto, cada nivel oculta a los niveles superiores la existencia de determinadas estructuras de datos, operaciones y hardware. La principal dificultad con el método de niveles es la de definir apropiadamente los diferentes niveles. Dado que un nivel sólo puede usar los servicios de los niveles inferiores, es necesario rea lizar una planificación cuidadosa. Por ejemplo, el controlador de dispositivo para almacenamien to de reserva (espacio en disco usado por los algoritmos de memoria virtual) debe estar en un nivel inferior que las rutinas de,gestión de memoria, dado que la gestión de memoria requiere la capacidad de usar el almacenamiento de reserva. (los usuarios) shells y comandos compiladores e Intérpretes bibliotecas del sistema interfaz de llamadas al sistema con el kemel señales,, gestión de sistema de archivos, planificación de CPU, terminales, sistema de intercambio, sistema de sustitución de páginas E/S de caracteres, E/Sde bloqueo, paginación bajo demanda controladores controladores de memoria virtual de terminal disco y cinta interfaz del kemel con el hardware controladores controladores de controladores de terminales. dispositivos, de memoria, terminales discos y cintas memoria física 2.7 Estructura del sistema operativo 55 Figura 2.12 Un sistema operativo estructurado en niveles. Otros requisitos pueden no ser tan obvios. Normalmente, el controlador de almacenamiento de reserva estará por encima del planificador de la CPU, dado que el controlador puede tener que esperar a que se realicen determinadas operaciones de E/S y la CPU puede asignarse a otra tarea durante este tiempo. Sin embargo, en un sistema de gran envergadura, el planificador de la CPU puede tener más información sobre todos los procesos activos de la que cabe en memoria. Por tanto, esta información puede tener que cargarse y descargarse de memoria, requiriendo que el controlador de almacenamiento de reserva esté por debajo del planificador de la CPU. Un último problema con las implementaciones por niveles es que tienden a ser menos eficien tes que otros tipos de implementación. Por ejemplo, cuando un programa de usuario ejecuta una operación de E/S, realiza una llamada al sistema que será capturada por el nivel de E/S, el cual llamará al nivel de gestión de memoria, el cual a su vez llamará al nivel de planificación de la CPU, que pasará a continuación la llamada al hardware. En cada nivel, se pueden modificar los pará metros, puede ser necesario pasar datos, etc. Cada nivel añade así una carga de trabajo adicional a la llamada al sistema; el resultado neto es una llamada al sistema que tarda más en ejecutarse que en un sistema sin niveles. Estas limitaciones han hecho surgir en los últimos años una cierta reacción contra los sistemas basados en niveles. En los diseños más recientes, se utiliza un menor número de niveles, con más funcionalidad por cada nivel, lo que proporciona muchas de las ventajas del código modular, a la vez que se evitan los problemas más difíciles relacionados con la definición e interacción de los niveles. 2 .7 .3 M icrokerne ls Ya hemos visto que, a medida que UNIX se expandía, el kemel se hizo grande y difícil de gestio nar. A mediados de los años 80, los investigadores de la universidad de Camegie Mellon desarro llaron un sistema operativo denominado Mach que modularizaba el kemel usando lo que se denomina microkemel. Este método estructura el sistema operativo eliminando todos los compo nentes no esenciales del kemel e implementándolos como programas del sistema y de nivel de usuario; el resultado es un kemel más pequeño. No hay consenso en lo que se refiere a qué servi cios deberían permanecer en el kemel y cuáles deberían implementarse en el espacio de usuario. Sin embargo, normalmente los microkernels proporcionan una gestión de la memoria y de los pro cesos mínima, además de un mecanismo de comunicaciones. Capítulo 2 Estructuras de sistemas operativos La función principal del microkernel es proporcionar un mecanismo de comunicaciones entre ei programa cliente y los distintos servicios que se ejecutan también en el espacio de usuario. La comunicación se proporciona mediante paso de mensajes, método que se ha descrito en la Sección 2.4.5. Por ejemplo, si el programa cliente desea acceder a un archivo, debe interactuar con el ser vidor de archivos. El programa cliente y el servicio nunca interactúan .directamente, sino que se comunican de form a indirecta intercambiando mensajes con el microkernel: Otra ventaja del método de microkernel es la facilidad para ampliar el sistema operativo. Todos los servicios nuevos se añaden al espacio de usuario y, en consecuencia, no requieren que se modi fique el kernel. Cuando surge la necesidad de modificar el kernel, los cambios tienden a ser pocos, porque el microkernel es un kernel m uy pequeño. El sistema operativo resultante es más fácil de portar de un diseño hardware a otro. El microkernel también proporciona más seguridad y fiabili dad, dado que la m ayor parte de los servicios se ejecutan como procesos de usuario, en lugar de como procesos del kernel. Si un servicio falla, el resto del sistema operativo no se ve afectado. Varios sistemas operativos actuales utilizan el método de microkernel. Tru64 UNIX (antes Digital UNIX) proporciona una interfaz UNIX al usuario, pero se implementa con un kernel Mach. El kernel Mach transforma las llamadas al sistema UNIX en mensajes dirigidos a los servicios apropiados de nivel de usuario. Otro ejemplo es QNX. QNX es un sistema operativo en tiempo real que se basa también en un diseño de microkernel. El microkernel de QNX proporciona servicios para paso de mensajes y plani ficación de procesos. También gestiona las comunicaciones de red de bajo nivel y las interrupcio nes hardware. Los restantes servicios de QNX son proporcionados por procesos estándar que se ejecutan fuera del kernel, en modo usuario. Lamentablemente, los m icrokem els pueden tener un rendimiento peor que otras soluciones, debido a la carga de procesamiento adicional impuesta por las funciones del sistema. Considere mos la historia de W indows NT: la primera versión tenía una organización de microkernel con nive les. Sin embargo, esta versión proporcionaba un rendimiento muy bajo, comparado con el de W indows 95. La versión Windows NT 4.0 solucionó parcialmente el problema del rendimiento, pasando diversos niveles del espacio de usuario al espacio del kernel e integrándolos más estre chamente. Para cuando se diseñó W indows XP, la arquitectura del sistema operativo era más de tipo monolítico que basada en microkernel. 2.7 .4 Módulos Quizá la mejor metodología actual para diseñar sistemas operativos es la que usa las técnicas de program ación orientada a objetos para crear un kernel modular. En este caso, el kernel dispone de un conjunto de com ponentes fundam entales y enlaza dinámicamente los servicios adicionales, bien durante el arranque o en tiempo de ejecución. Tal estrategia utiliza módulos que se cargan dinám icam ente y resulta habitual en las implementaciones modernas de UNIX, como Solaris, Linux y M ac OS X. Por ejem plo, la estructura del sistema operativo Solaris, mostrada en la Figu ra 2.13, está organizada alrededor de un kernel central con siete tipos de módulos de kernel car- gables: 1. Clases de planificación 2. Sistemas de archivos 3. Llamadas al sistema cargables 4. Formatos ejecutables 5. M ódulos STREAMS 6. Módulos misceláneos 7. Controladores de bus y de dispositivos Un diseño así permite al kernel proporcionar servicios básicos y también permite implementar ciertas características dinámicamente. Por ejemplo, se pueden añadir al kernel controladores de 2.7 Estructura del sistema operativo 57 Figura 2.13 Módulos cargables de Solaris. bus y de dispositivos para hardware específico y puede agregarse como módulo cargable el soporte para diferentes sistemas de archivos. El resultado global es similar a un sistema de nive les, en el sentido de que cada sección del kemel tiene interfaces bien definidas y protegidas, pero es más flexible que un sistema de niveles, porque cualquier módulo puede llamar a cualquier otro módulo. Además, el método es similar a la utilización de un microkernel, ya que el módulo princi pal sólo dispone de las funciones esenciales y de los conocimientos sobre cómo cargar y comuni carse con otros módulos; sin embargo, es más eficiente que un microkernel, ya que los módulos no necesitan invocar un mecanismo de paso de mensajes para comunicarse. El sistema operativo Mac OS X de las computadoras Apple Macintosh utiliza una estructura híbrida. Mac OS X (también conocido como Darwin) estructura el sistema operativo usando una técnica por niveles en la que uno de esos niveles es el microkernel Mach. En la Figura 2.14 se mues tra la estructura de Mac OS X. Los niveles superiores incluyen los entornos de aplicación y un conjunto de
Compartir