Introducción a los sistemas operativos

Introducción

Un sistema operativo es un programa que actúa de intermediario entre el usuario y el hardware de un ordenador. Para entender bien lo que significa e implica esta afirmación empezaremos por ver la evolución que han tenido los programas de ayuda para la utilización de los ordenadores. En este recorrido iremos desde los albores del cálculo automático a las últimas técnicas de procesamiento paralelo y distribuido, aprovechando al mismo tiempo para establecer algunos conceptos básicos de los sistemas operativos, como sistemas batch, multiprogramación, tiempo compartido, tiempo real, etc.

Como ya hemos apuntado, el sistema operativo permite la utilización del ordenador de una forma apropiada y eficiente, así, veremos al final del capítulo los servicios que presta el sistema operativo, haciendo especial hincapié en los ofrecidos al programador, mediante las llamadas al sistema.

Evolución de los Sistemas Operativos

En primer lugar empezaremos por ver la evolución que han sufrido los programas de interfaz entre el hardware y el usuario, para poder llegar de una forma fácil al siguiente apartado, que nos explica Qué es un sistema operativo. Comenzaremos mencionando, a modo de anécdota, algunas fechas históricas en el desarrollo del cálculo automático, posteriormente veremos que al llegar la segunda generación de ordenadores comienzan a surgir programas de ayuda al usuario, momento en el que empezaremos a comentar realmente la evolución de los sistemas operativos.

Todo empezó cuando

  • alrededor del año 4000 a.C. se inventó el mecanismo de cálculo más antiguo conocido: el ábaco. Este dispositivo, cuyo origen no está claramente determinado (griego, japonés o chino) puede utilizarse para sumar, restar, multiplicar y dividir. Se dice que en las manos de un operador experto puede producir resultados tan rápidamente como con una moderna calculadora de bolsillo.

  • 1645. Blaise Pascal, el filósofo, físico y matemático francés desarrolla la primera calculadora mecánica, la cual servía para realizar sumas y restas de números decimales.

  • 1671. El matemático prusiano Barón Gottfried Wilhelm von Leibniz mejora la calculadora de Pascal, añadiéndole las operaciones de multiplicación y división.

  • 1823. El inventor inglés Charles Babbage concibe la Máquina de Diferencias, la cual mediante tablas de datos y la suma como única operación, permitía el cálculo de un gran número de funciones mediante una técnica llamada Método de las Diferencias Finitas. El proyecto fue abandonado en 1842. Un motivo fue la falta de la tecnología mecánica necesaria para su realización. Otra razón fue la pérdida de interés de Babbage cuando se le ocurrió una máquina mucho más potente: la Máquina Análitica. A diferencia de la máquina de diferencias finitas, la máquina analítica estaba pensada para realizar automáticamente cualquier operación matemática.

    • Constaba de dos partes principales: El Molino y el Almacen. El molino era la unidad aritmético-lógica, y el almacén realizaba las funciones de la memoria. El molino se alimentaba con tarjetas de operaciones (+, -, x, ÷) que se realizaban en cada paso del programa, mientras que el almacén se alimentaba con tarjetas que contenían las variables, y tenía capacidad para 1000 números decimales de 50 dígitos. Esta máquina incluía la posibilidad de alterar automáticamente la secuencia de ejecución de las instrucciones, o lo que es lo mismo, disponía de instrucciones o medios de bifurcación condicional. Se estimó que la suma de dos números tardaría un segundo, y la multiplicación, un minuto.

    • Aunque la Máquina Analítica no paso de ser un diseño, y solamente una pequeña parte pudo construirse y hacerse realidad, el mérito de Babbage estriba en haber sentado las bases de los actuales ordenadores, constituidos por una o varias unidades de cálculo (UAL) y una zona para el almacenamiento para instrucciones y datos.

  • 1887. Hermann Hollerith inventa la tarjeta perforada (basado en la idea de Babbage) y la aplica a la Máquina Tabuladora de Tarjetas Perforadas, que es utilizada con gran éxito en la realización del censo de Estados Unidos de 1890. En 1896 Hollerith forma la Computing-Tabulating-Recording Corporation, que en 1924 cambiaría su nombre a International Business Machines.

  • 1934. John Vincent Atanasoff desarrolla en la Universidad de Iowa (U.S.A.) el primer prototipo de ordenador electrónico: el $%&. Está construido con tubos de vacío que reemplazan a los relés electromagnéticos que se venían utilizando.

  • 1941. Konrad Zuse construye en Alemania el Z3, el primer ordenador de propósito general controlado por programa.

La Primera Generación

Con el cambio de los dispositivos electromecánicos a los electrónicos (válvulas o tubos de vacío), comienza la primera generación de ordenadores, en la que estos eran tan grandes como poco fiables. Utilizaban válvulas que generaban una gran cantidad de calor, por lo que requerían estancias con un espacio muy considerable.

Aunque eran mucho más rápidos que sus antecesores mecánicos o electromecánicos, resultaban muy lentos comparados con los de hoy día, además de tener muy limitada su capacidad de memoria.

La tarjeta perforada de Hollerith era el medio para introducir en el ordenador tanto los datos como los programas escritos en código máquina. Más tarde se utilizó el tambor magnético, similar a los discos actuales pero utilizando como superficie magnética un cilindro en lugar de un disco.

Casi todos los ordenadores de esta generación se programaron en lenguaje máquina, aunque al final se desarrollaron los lenguajes simbólicos (ensambladores) que ofrecían instrucciones con códigos nemotécnicos.

La principal utilización de los ordenadores era en el ámbito científico y en centros o laboratorios de investigación de universidades. Posteriormente comenzaron a ofrecerse comercialmente ordenadores de propósito general.

  • 1943. John W. Mauchly y J.P. Eckert, de la Universidad de Pennsylvania construyen el ENIAC, de 30 toneladas de peso, formado por 18.000 tubos de vacío, 70.000 resistencias y 10.000 condensadores. Su capacidad de almacenamiento era de 20 números de 10 dígitos, y utilizaba un reloj de 100 KHz., pudiendo realizar 5.000 sumas o 300 multiplicaciones por segundo. Cuando se entregó en 1946 supuso un gran avance en cuanto a potencia de cálculo.

  • 1945. John von Neumann recomienda la utilización del sistema binario de numeración en el diseño de ordenadores. También propone que tanto las instrucciones de control como los datos estén almacenados en el ordenador. Estas propuestas se materializan en el EDSAC construido en 1949 en la Universidad de Cambridge.

  • 1948. Se lanza el IBM 604. Puede leer tarjetas perforadas, realizar cálculos y ofrecer los resultados en tarjetas perforadas. Realizaba las operaciones utilizando registros electrónicos. Se programaba con tarjetas cableadas (plugboards), o sea, que el programa no estaba almacenado en memoria.

  • 1951. Se entrega el UNIVAC-1, el primer ordenador electrónico digital de programa almacenado en memoria que está disponible comercialmente.

  • 1953-1956. IBM lanza la serie 700. Es de resaltar el 704, primer ordenador comercial con un programa de control, que era un rudimentario sistema operativo.

    • El 709 disponía de procesadores especializados en el control de las operaciones de entrada/salida que se denominaban canales. En las máquinas anteriores, todas las operaciones de E/S las realizaba directamente la CPU.

La Segunda Generación

La segunda generación de ordenadores está marcada por el descubrimiento del transistor en 1948 por los laboratorios de la Bell Telephone. En 1954, estos mismos laboratorios construyen el TRADIC, primer ordenador digital transistorizado.

Hasta ahora, poca o ninguna ayuda se le ofrecía al usuario del ordenador, que no era otro sino el propio programador. Éste se encargaba no solamente de escribir los programas en lenguaje máquina, o como mucho en un lenguaje simbólico (ensamblador), sino que también tenía que ocuparse de cargar el programa apropiadamente en la memoria, de una forma manual, mediante los botones y controles del panel de control; seguidamente tenía que controlar la ejecución del programa atendiendo a las luces de la consola. Si se producía algún error, tenía que detener la ejecución del programa e intentar detectar el motivo del error examinando el contenido de las direcciones de memoria y de los registros de la CPU.

Poco a poco se asientan los ensambladores, montadores o enlazadores (linkers) y cargadores para facilitarle la tarea al sufrido programador. También comienzan a construirse bibliotecas de funciones comunes, dando así los primeros pasos en la reutilización del software. Igualmente, también se ofrecen los GULYHUV (programas de gestión de los dispositivos periféricos), aunque no de forma automática, como en la actualidad, sino mediante bibliotecas de funciones de E/S que simplemente facilitan las operaciones con los periféricos.

A mediados de los años 50 IBM desarrolla el primer lenguaje de alto nivel:

FORTRAN (Formula Translator), especialmente ideado para aplicaciones científicas.

En 1959 nace COBOL, lenguaje orientado a la gestión de grandes aplicaciones comerciales. También aparecen otros lenguajes, como ALGOL y APL.

No obstante, los lenguajes de alto nivel no resultaban tan prácticos como hoy día, ya que se limitaban a traducir a lenguaje ensamblador. Así, la ejecución de un programa escrito en FORTRAN requería los siguientes pasos:

  1. Cargar la cinta con el compilador de FORTRAN

  2. Compilar el programa fuente FORTRAN

  3. Descargar la cinta del compilador

  4. Cargar la cinta del ensamblador

  5. Ensamblar el programa producido por el compilador

  6. Descargar la cinta del ensamblador

  7. Cargar el programa objeto producido por el ensamblador

  8. Ejecutar el programa objeto.

Si se producía un error en cualquiera de estos pasos, había que volver a comenzar por el principio.

Por aquel entonces los ordenadores eran tan escasos como caros, y su mantenimiento (alimentación eléctrica, aire acondicionado, programadores, etc.) les encarecían aún más. Nos encontramos, por tanto, con que el tiempo de ordenador era extremadamente valioso, por lo que se debe aprovechar lo más posible, es decir, se requiere un alto índice de utilización para sacar provecho de la inversión.

Por desgracia, como hemos visto, el proceso de puesta a punto de un programa era un verdadero problema, y no olvidemos que mientras se montaban o desmontaban las cintas o el programador operaba con los mandos de la consola, la CPU estaba ociosa. En resumen: se desperdiciaba el tiempo de ordenador.

Se necesitaba hacer algo para mejorar el aprovechamiento del tiempo de CPU. La solución vino por dos vertientes:

Se requieren los servicios de un operador profesional. El programador ya no se encarga de operar en la consola, de cargar cintas y del proceso de traducción. De esto se encarga un experto en estas tareas, que las realiza con mayor rapidez y con menor gasto, pues la hora de operador resulta más barata que la del programador, que ahora solamente se encarga de escribir y depurar programas.

Se reduce el tiempo de puesta a punto. Esto se consigue organizando mejor el trabajo, esto es, los trabajos con necesidades similares se agrupan y se ejecutan por lotes (batch); por ejemplo, si el operador recibe encargos para compilar un programa de FORTRAN, luego uno de COBOL, y después otro de FORTRAN, en lugar de compilarlos en ese orden (lo que implicaría cargar dos veces el compilador de FORTRAN), compila primero los dos programas de FORTRAN y a continuación el de COBOL, con lo que se ahorra el tiempo de una carga del compilador de FORTRAN.

Aunque las cosas han mejorado con la ayuda del operador, que ordena los trabajos pedidos por los programadores, todavía se pierde mucho tiempo en los preparativos de carga y ejecución. Por ejemplo, si durante la ejecución de un programa, éste se paraba de forma imprevista, el operador debía anotar el estado de luces e indicadores de la consola, y producir un volcado de memoria si lo consideraba necesario. Durante todo este tiempo, la CPU seguía ociosa, o sea, desaprovechada.

Para superar este problema, se desarrolló lo que podríamos considerar como un rudimentario sistema operativo: la Secuenciación Automática de Trabajos. Esto consiste en un programa llamado Monitor que constaba de tres partes:

  • Cargador

  • Secuenciador de Trabajos

  • Intérprete de las Tarjetas de Control

El Monitor, que estaba siempre residente en el ordenador, se encargaba de ir cargando y transfiriendo el control de un trabajo a otro de forma automática, es decir, sin la intervención del operador. Cada trabajo suministrado por el programador estaba formado por un lote de tarjetas perforadas, y lo que se hacía era situar delante de cada lote unas tarjetas de control adicionales indicando lo que se debía hacer con el lote que seguía. Estas tarjetas las interpretaba el Monitor y obraba en consecuencia, cargando compiladores y ensambladores, ejecutando programas, etc.

Ahora tenemos que el ciclo de carga de compiladores, traducción, ejecución e impresión de los resultados se realiza sin intervención del operador, con lo que el tiempo que ha transcurrido desde que el programador entregó su trabajo hasta que obtuvo los resultados es el correspondiente al de 1) espera de turno, 2) traducción y 3) ejecución del programa; eliminando las esperas debidas a las lentas acciones manuales del operador.

El gran problema que teníamos hasta ahora era la ralentización que generaba la intervención humana debido a su lentitud. Aunque los sistemas batch acaban con esta dificultad, todavía hay más trabas para evitar que la CPU esté ociosa a menudo. Resulta que la velocidad de los dispositivos de E/S (de naturaleza mecánica) son mucho más lentos que los circuitos electrónicos de la CPU, que ejecuta millones de instrucciones por segundo, mientras que una lectora de tarjetas no leía más de 1.200 tarjetas en un minuto. Con el paso del tiempo la tecnología logró verdaderas mejoras en la velocidad de los dispositivos de E/S, pero nunca comparables con los progresos realizados con las CPU’s, cuya velocidad se incrementaba mucho más rápido. Así que el problema no solamente no se solucionaba, sino que se acentuaba aún más.

Lo más que se pudo hacer para solucionar este desaprovechamiento del tiempo de CPU fue descomponer en dos fases los procesos de E/S. A principios de los años 60 el dispositivo normal de entrada de datos era el lector de tarjetas perforadas, mientras que el resultado del tratamiento se dirigía a una impresora (se utilizaban pues, dos de los periféricos más lentos). Pues bien, la mejora consistió en hacer que en lugar de que la CPU leyese los datos de entrada de la tarjeta perforada y enviase los resultados a una impresora, primero, con ayuda de un ordenador más lento y barato, se leían las tarjetas y se copiaban a una cinta magnética; posteriormente se llevaba la cinta al ordenador principal y se leían los datos (ahora a mucha más velocidad que utilizando un lector de tarjetas). Los datos de salida se enviaban igualmente a una cinta magnética, la cual se volcaba más tarde a una impresora con ayuda del otro ordenador de bajas prestaciones. Este tratamiento diferido de la información se denomina proceso off-line.

Lo malo de este tratamiento off-line es el retardo que se introduce para ejecutar un trabajo concreto, pues en lugar de leerlo directamente de las tarjetas perforadas, primero hay que pasarlo a una cinta magnética, esperar a que la cinta se llene con trabajos y después llevar la cinta al ordenador. Aunque esto parece muy engorroso, no lo es tanto si pensamos que se trata de sistemas batch, en los que no se requieren los tiempos de respuesta a los que estamos acostumbrados hoy día.

El problema de los sistemas off-line era que no se podían copiar tarjetas perforadas al final de la cinta mientras la CPU leía desde el principio; en su lugar, primero había que escribir la cinta entera, rebobinarla y a continuación empezar a leerla (ahora ya en el ordenador principal). Esto se debe a la propia naturaleza del dispositivo, que es de acceso secuencial. Pronto aparecieron los discos magnéticos (dispositivo clásico de acceso directo), con lo que se eliminó el problema de las cintas. Ya que la cabeza de lectura puede moverse rápidamente a cualquier posición del disco, ésta puede cambiar rápidamente del área del disco donde se están añadiendo los datos de las tarjetas perforadas, al lugar donde la CPU quiere leer la siguiente información de entrada. A este tipo de proceso se le denomina SPOOL (Simultaneous Peripheral Operation On Line).

La esencia de este tratamiento consiste en utilizar el disco como un gran buffer en el que se van metiendo por adelantado tanto todos los datos de entrada posibles, como los datos de salida, donde permanecen hasta que los dispositivos de salida (impresora, plotter, etc.) están listos para recibirlos, es decir, se solapa la E/S de un trabajo con el cálculo de otros trabajos. De esta manera, con un disco y la ayuda de unas tablas en las que se van apuntando los trabajos que entran, la CPU no tiene que permanecer “en espera” hasta que un dispositivo de E/S está dispuesto a suministrar o aceptar un dato solicitado o generado por ella.

La Tercera Generación

A 1965 se le considera el año del comienzo de la tercera generación de ordenadores, caracterizada, sobre todo, por el descubrimiento del Circuito Integrado (a principios de los años 60) que reemplazó a los transistores. Esto trajo consigo el nacimiento de las memorias de semiconductores, que aumentaron considerablemente de capacidad y sustituyeron a las de núcleos de ferrita.

A modo de anecdotario podemos decir que la famosa serie de ordenadores Sistema 360 de IBM (a base de transistores) que se lanzó al mercado en 1964, fue sustituida en 1970 por la línea del Sistema 370 que ya estaba construida con circuitos integrados.

Estas innovaciones en el hardware trajeron consigo los correspondientes cambios en los programas que sobre él se ejecutaban. Veamos seguidamente las repercusiones que tuvieron los avances tecnológicos sobre los sistemas operativos.

Multiprogramación

Cuando los trabajos venían en tarjetas perforadas, o incluso en cinta magnética, solamente había un orden de ejecución de los mismos: primero en llegar - primero en servir. Sin embargo, con la aparición de los sistemas SPOOL, ahora se dispone en todo momento de una serie de trabajos en un dispositivo de acceso directo (el disco) esperando a ser ejecutados, y puesto que se puede elegir y acceder a cualquiera de ellos, esto hace que ahora sí se pueda realizar una planificación de trabajos distinta de la de primero en llegar - primero en servir. En el capítulo dedicado a la gestión de procesos se tratan en profundidad distintas políticas de planificación.

Hasta ahora, cuando se le asignaba la CPU a un trabajo, éste se apropiaba de ella hasta finalizar completamente su ejecución, incluyendo los tiempos muertos de espera a que finalicen operaciones de E/S. Ahora, que además ya se dispone de una cantidad considerable de memoria principal, se pueden seleccionar varios trabajos del disco duro y cargarlos en memoria principal. Cuando el trabajo en ejecución realiza una operación de E/S, en lugar de tener la CPU ociosa en espera de que finalice dicha operación, se puede seleccionar otro de los trabajos cargados en memoria y asignarle la CPU. De esta manera se aprovecha mucho más el tiempo, pues siempre que haya trabajos pendientes, la CPU nunca está ociosa.

Así, tenemos que varios trabajos pueden estar cargados en memoria, que se han comenzado a ejecutar y que evolucionan conjuntamente. Cuando en un ordenador se ejecutan trabajos de esta manera, se dice que utiliza multiprogramación.

En este punto conviene que nos demos cuenta de que para llevar a cabo la multiprogramación, el sistema operativo no solamente tiene que realizar la elección y el orden de los trabajos a cargar en memoria, sino que también se debe ocupar de gestionar la ocupación de la memoria principal, llevando la cuenta de los espacios libres y ocupados, y eligiendo distribuciones que permitan un buen aprovechamiento de la misma. De igual forma, también tiene que encargarse de la gestión de la CPU, es decir, de su distribución entre los distintos trabajos en ejecución, de acuerdo con la política de planificación establecida.

Como vemos, el trabajo del sistema operativo empieza a complicarse a medida que tiene que ir tomando decisiones que antes le competían exclusivamente al usuario.

Tiempo Compartido

Si recordamos, al principio los ordenadores eran sistemas interactivos, de hecho, el programador se encargaba de todo:

  • Alimentar las tarjetas perforadas.

  • Establecer adecuadamente los conmutadores de la consola.

  • Controlar la ejecución mediante los mensajes que pudieran aparecer en el terminal de la consola.

  • En caso de errores de ejecución, provocar los volcados de memoria que ayudaban a descubrir los fallos del programa.

El problema que había con estos sistemas era el desperdicio de tiempo de ordenador.

Por el contrario, con los sistemas batch se aprovechan muy bien los recursos, pues no hay tiempos muertos con la CPU ociosa. No obstante, en estos sistemas lo que se ha perdido es la interacción entre el usuario (normalmente era el programador) y la máquina, pues como hemos visto, una vez que se le encarga un trabajo al sistema (la ejecución de un programa) éste se realiza automáticamente sin intervención humana y sin pérdidas de tiempo inútiles.

El inconveniente de tanto automatismo es precisamente la pérdida de la interacción con la máquina. Debido a esta falta de interacción resulta que ahora se tarda mucho tiempo en poner a punto un programa, dado que se tarda mucho en conseguir compilar un programa sin errores, pues el ciclo de

  1. Solicitar la compilación del programa y esperar a que tenga lugar su compilación.

  2. Realizar la compilación y esperar a que el listado de errores salga por la impresora, y

  3. Corregir los errores.

conlleva mucho tiempo de espera por parte del usuario.

Incluso una vez que se ha conseguido traducir el programa, es decir, se tiene sin errores de compilación, queda la parte más compleja de su puesta a punto, o sea, la depuración de los errores de ejecución.

Y esto se debe, como ya hemos apuntado, al hecho de que el programador no puede seguir de cerca cada una de las fases del ciclo de puesta a punto de los programas. Por tanto, lo que se hace necesario es una comunicación más directa del usuario tanto con el sistema operativo como con su propio programa, de tal forma que obtenga respuestas inmediatas a cualquiera de las ordenes o comandos suministrados al sistema.

Para conseguir esto se requiere, por una parte, que los mensajes del sistema o los resultados de salida del programa no vayan a parar a la cola de trabajos de impresión, sino que vayan directamente a la pantalla del terminal de usuario, y cuando el sistema operativo acabe la ejecución de un comando (o trabajo) busque la siguiente “sentencia de control” no en la siguiente tarjeta o imagen de tarjeta grabada en el disco, sino en el teclado del usuario, para que le indique la siguiente acción. Por otra parte, tenemos un sistema multiprogramado en el que se están ejecutando varios programas cuasi-simultáneamente, donde cada uno de ellos posiblemente corresponde a un usuario distinto. Pues bien, para que cada uno de estos usuarios no sufra grandes esperas lo que se debe hacer es aplicar una política de planificación según la cual la CPU se reparta por turno circular entre todos los procesos en porciones de tiempo muy pequeñas. Al disponer en cada turno de muy poco tiempo de CPU, ciertamente no se realiza mucho trabajo a un usuario dado, pero también asegura que se le dedicará poco tiempo al resto de los usuarios, con lo que enseguida le volverá a corresponder el turno de CPU a tal usuario, dando lugar a que dé la sensación de disponer de un sistema dedicado.

Aunque las porciones de tiempo sean pequeñas, esto no suele ser perceptible por los usuarios (a no ser que sea muy elevado su número), pues la velocidad de escritura en un teclado, por muy alta que sea para algunas personas (5 pulsaciones por segundo) resulta extremadamente lenta para la velocidad de la CPU, por lo que entre una pulsación y la siguiente corresponden varias porciones de CPU, con lo que se asegura que al pulsar una tecla, inmediatamente se recoge y se hace eco en la pantalla, ofreciendo así el deseado efecto de máquina dedicada.

Cuando un programa está pendiente de que el usuario le indique una orden en el teclado, si el usuario tarda en teclear dicha orden, el sistema operativo en lugar de malgastar las porciones de tiempo que le corresponden, esperando en vano una respuesta del usuario, lo que hace es conmutar de proceso dándole la CPU a cualquier proceso dispuesto a ejecutar instrucciones en ella. Y no vuelve a ofrecerle porciones de CPU hasta que no se detecta que el usuario ha comenzado a escribir en el terminal.

El primer sistema operativo de tiempo compartido fue el CTSS desarrollado en el MIT por Corbato y otros en 1962, aunque no se hizo popular hasta que llegó el soporte hardware adecuado que proporcionaron los avances técnicos de las tercera generación. Posteriormente se hizo famoso un sistema operativo muy ambicioso que quería soportar simultáneamente cientos de usuarios: MULTICS, de los Laboratorios Bell. Ken Thomson fue uno de los ingenieros que trabajaron en el desarrollo de MULTICS, quien posteriormente desarrolló una versión monousuario (inicialmente), dando lugar al conocido UNIX.

Sistemas Paralelos

Hasta ahora nos hemos estado preocupando de aprovechar al máximo el uso de un ordenador, de tal forma que haya el mínimo tiempo muerto en la utilización de la CPU. Sin embargo, hay ciertas aplicaciones o programas que, por sus características de ejecución, no solamente dejan muy poco tiempo ociosa a la CPU, sino que además requieren una gran velocidad de ésta para obtener un mínimo tiempo de respuesta. Este es el caso de ciertas aplicaciones científicas o de cálculo numérico.

Así, debido a esta demanda de velocidad surgieron los Sistemas Paralelos, es decir, ordenadores que contienen varios procesadores principales trabajando de forma conjunta bajo la batuta de un mismo reloj, compartiendo el bus y dispositivos periféricos y, en determinadas configuraciones, incluso la memoria principal. Debido a este “hermanamiento” entre todos los procesadores, en el que comparten los recursos del sistema de una forma tan directa, a este tipo de arquitectura se le conoce con el nombre de sistemas muy acoplados.

Parece razonable que si en un sistema ponemos cuatro procesadores en lugar de uno solo, el trabajo a realizar se puede repartir entre ellos, rebajándose drásticamente el tiempo de espera. Sin embargo, no debemos pensar que si se multiplica por Q el número de procesadores, igualmente se multiplica por Q el factor de aceleración. Desde luego, la aceleración es bastante menor de lo esperado, debido a dos factores principales:

  1. La sobrecarga que supone la gestión para la división del trabajo a realizar y el tiempo necesario para la comunicación y sincronización entre los distintos procesadores que cooperan en la realización de un trabajo.

  2. La contención en el uso de los recursos y periféricos compartidos, pues puede ser que cuando un procesador requiere un acceso a la memoria o una lectura de un periférico, éstos estén ocupados por otro de los procesadores.

Sabemos que para escribir un programa, cuatro programadores de forma conjunta no tardan cuatro veces menos que uno solo, sino bastante más.

Para cierto tipo de trabajos, incluso puede resultar más económico disponer de una máquina con varios procesadores que tener varios ordenadores, pues en el primer caso se comparten recursos, en lugar de tenerlos repetidos y con una baja utilización.

Sin embargo, no suele ser la economía la razón principal de los sistemas paralelos, sino los requisitos de rapidez, como ya hemos dicho, y en otros casos, la necesidad de disponer de sistemas fiables. Hay determinados entornos, especialmente los denominados Sistemas Empotrados (o embarcados) que requieren una altísima fiabilidad de funcionamiento. Este es el caso de los programas de control que llevan los aviones, naves espaciales o misiles nucleares. Como podemos imaginar, un simple error en su funcionamiento puede acarrear muy trágicas consecuencias.

Por esto, aquí no es importante la economía, sino la fiabilidad. Así, si en un sistema se dispone de varios procesadores que tienen el mismo cometido, aunque falle uno de ellos, puede continuar cualquiera de los restantes; o en caso de tener distintos trabajos asignados, puede repartirse la carga del procesador estropeado entre los demás, de tal forma que, aunque pueda degradarse la velocidad general, el resultado no es catastrófico. En otros casos en los que hay que realizar cálculos, éstos se les encargan a todos los procesadores, o sea, todos los procesadores intentan obtener el resultado. Al final, mediante una votación se elige el resultado que hayan obtenido la mayoría de los procesadores, dando por supuesto que es el más fiable.

En lo que al sistema operativo se refiere, hay dos filosofías en el diseño de sistemas paralelos:

  • Sistemas Simétricos

  • Sistemas Asimétricos

El modelo simétrico de sistema multiprocesador es el más común de los utilizados hoy día. En este enfoque, en cada CPU se ejecuta una copia idéntica del sistema operativo. Un ejemplo de este sistema es la versión de Unix para ordenadores Encore.

En el multiproceso asimétrico, cada procesador tiene asignadas tareas específicas.

En este caso, se requiere que uno de los procesadores haga las funciones de Maestro que controla y supervisa el sistema, y se encarga de repartir el trabajo.

En el capítulo dedicado a la gestión de procesos se tratarán las distintas políticas de reparto de CPU’s en estos sistemas multiprocesadores.

Es importante darse cuenta de que el hecho de que un sistema sea simétrico o asimétrico no depende exclusivamente del hardware. Es posible que sobre un sistema con procesadores iguales se dispongan sistemas operativos distintos (por lo que, al fin y al cabo, acaban ofreciendo servicios distintos), o que sobre un entorno con CPU’s distintas se ejecuten sobre cada una de ellas distintas versiones de un mismo sistema operativo (por ejemplo, Unix), con lo que entonces todos acaban ofreciendo los mismos servicios: los que ofrece Unix.

Sistemas Distribuidos

A la hora de distribuir el cálculo entre varios procesadores, existe otra opción en contraste con la vista anteriormente de los sistemas muy acoplados, en la cual los procesadores no comparten ni memoria ni reloj: Sistemas Distribuidos.

Un entorno distribuido está formado por diversos subsistemas, donde cada uno de ellos está formado por un procesador que dispone de su propio reloj y memoria local, y, por supuesto, cada uno dispone de sus propios dispositivos de E/S. Estos subsistemas están conectados entre sí mediante líneas de comunicación, normalmente, de alta velocidad; formando, por tanto, una red de ordenadores de área local.

En este nuevo enfoque de sistemas multiprocesadores, cada uno de los procesadores no depende de los otros de una manera tan cerrada como en el caso de los sistemas paralelos. De hecho, puede darse el caso de que uno de los subsistemas esté fuera de servicio sin que por ello afecte al resto de los componentes de la red. Démonos cuenta que si en un sistema paralelo la memoria principal falla, todos los procesadores quedan fuera de servicio. Dada esta falta de dependencia entre ellos, a los sistemas distribuidos también se les dice que están poco acoplados.

Dado que los sistemas están tan poco acoplados, cada uno de ellos puede ser muy distinto de los demás; así, podemos tener desde un pequeño ordenador personal, hasta un supercomputador vectorial. De esta manera tenemos una red de ordenadores multipropósito al servicio de cualquier usuario de dicha red.

Varios beneficios se derivan de los sistemas distribuidos:

  • Se comparten recursos.

    • No es necesario disponer de múltiples impresoras similares, se puede acceder a cualquier tipo de impresora que esté conectada a un nodo en servicio. Igualmente, se tiene acceso a cualquier dispositivo de E/S especializado y a ficheros, e incluso se tiene acceso a cualquier CPU del sistema para poder encargarle ciertos trabajos que no se pueden realizar en otro nodo, o porque simplemente está descargada de trabajo.

  • Mayor velocidad,

    • pues ciertos trabajos se pueden descomponer en varias tareas, y cada una de ellas enviarla a ejecutarse a ordenadores distintos y de forma paralela.

  • Fiabilidad.

    • Si un subsistema falla por cualquiera de sus componentes, el resto de los nodos pueden seguir operando con toda normalidad; a no ser que el subsistema inutilizado fuera crucial para la consecución de un cierto trabajo. No obstante, esto no sucede si se dispone de un cierto nivel de redundancia en los componentes de la red. Aunque también habíamos visto esta fiabilidad en los sistemas paralelos, obsérvese que, como ya hemos mencionado, si en estos últimos falla el reloj, el sistema entero queda inutilizado, mientras que si esto sucede en un sistema distribuido, simplemente se degrada un poco el sistema, o incluso puede que no tenga ninguna repercusión, al menos a corto plazo.

Sistemas de Tiempo Real

Hasta ahora hemos tratado de entornos con sistemas operativos de propósito general, sin embargo hay cierto tipo de trabajos que requieren sistemas operativos de propósito especial. Este es el caso de ciertas situaciones de la vida real en los que la rapidez del tratamiento de la información es importantísima, es decir, que ante una situación dada, el tiempo de respuesta del ordenador es crítico.

Como ejemplos, podemos citar a los sistemas de control de las centrales nucleares o dispositivos de control industrial, los sistemas electrónicos del control de guiado de los misiles, dispositivos de ayuda en automóviles (inyección electrónica, ABS y Airbag), sistemas de ayuda médica, etc. Estos ejemplos tienen algo en común: ante cualquier modificación de su entorno (normalmente controlado por sensores), el ordenador de control debe reaccionar con suma rapidez, pues de no ser así, las consecuencias pueden ser fatales o catastróficas. A los sistemas operativos que se utilizan en este tipo de circunstancias críticas en el tiempo se les denomina sistemas de tiempo real.

Démonos cuenta de que en un sistema de consulta de bases de datos, por ejemplo, nos gustaría que ante cualquier pregunta, la respuesta fuese rápida, pero está claro que si ésta tarda en aparecer, lo más que puede pasar, si es que somos impacientes, es que nos pongamos nerviosos, pero no pasa de ahí; de hecho, incluso aunque el sistema se quede inoperante antes de dar la respuesta, las consecuencias no suelen ser, ni mucho menos, irreparables.

En informática es difícil dar definiciones, por eso no vamos a proponer una para el tiempo real, pero si podemos decir cosas sobre él, como por ejemplo que "el sistema de tiempo real es aquel en el que si el proceso adecuado no se realiza dentro de unos límites de tiempo muy estrictos y muy pequeños, el sistema falla.

La interpretación de esta sentencia es bastante subjetiva, por eso, el concepto de tiempo real se suele entender mejor con los ejemplos anteriormente citados.

Atendiendo a lo estrictas que sean las restricciones temporales, se pueden considerar dos tipos de sistemas de tiempo real: los rigurosos y los moderados.

  • Tiempo Real Riguroso (hard real-time).

    • Los ejemplos que hemos mencionado arriba pertenecen a esta clase de tiempo real, o sea, sistemas que garantizan que las tareas críticas se realizan a tiempo. Para poder cumplir esta garantía, todos los tiempos que se invierten en la realización de cualquier tarea deben estar claramente establecidos y limitados, desde el tiempo que se tarda en realizar una lectura de la memoria RAM, al tiempo necesario para realizar cualquier servicio de los ofrecidos por el sistema operativo. Poder cumplir estas restricciones temporales tiene un precio; así, en estos sistemas rigurosos, no se suele disponer de memoria secundaria, pues los discos son extremadamente lentos, por lo que los datos suelen guardarse en memorias RAM o ROM. También suelen estar ausentes todas las características de alto nivel de los sistemas operativos, como por ejemplo, la gestión de memoria virtual, y por supuesto, nunca ofrecen servicios tales como el tiempo compartido.

  • Tiempo Real Moderado (soft real-time).

    • En estos sistemas las acotaciones en los tiempos de respuestas no son tan restrictivas como en el caso anterior, por eso pueden mezclarse las características del tiempo real con las de otros sistemas de propósito general. Áreas típicas de su aplicación son los entornos multimedia y la realidad virtual, en los cuales se necesita cierta funcionalidad de los sistemas operativos de propósito general que no pueden ofrecer los sistemas de tiempo real riguroso. En estos sistemas se requieren tiempos de respuesta cortos (por ejemplo para visualizar una película sin “parones”). No obstante, si por cualquier motivo en un momento dado no se cumplen los tiempos de respuesta deseados, las consecuencias no son catastróficas, simplemente producen un mal efecto, lo cual no es grave, sino simplemente indeseable. Unix, VMS y Windows NT son ejemplos de sistemas operativos de propósito general que ofrecen a su vez ciertas características de tiempo real moderado.

¿Qué es un Sistema Operativo?

El Sistema Operativo es un programa o conjunto de programas que constituyen una de las piezas fundamentales de un ordenador. Es tan fundamental y tiene tantos cometidos que se puede hablar mucho de él, sin embargo, como ya nos ha sucedido otras veces, resulta muy difícil dar una definición. Afortunadamente a nosotros no nos interesa su definición concreta, sino conocer sus funciones, los servicios que proporciona y, en general, sus características. Así, tal vez podamos efectuar algunas afirmaciones −no definiciones− sobre el sistema operativo.

Podemos pensar, por ejemplo, en algunas de las operaciones que habitualmente realizamos con un ordenador. Una de éstas puede ser cuando solicitamos que se muestre en la pantalla la lista de los ficheros de un disco o directorio, es decir, cuando tecleamos el comando dir de MS-DOS o ls de Unix. Como veremos más adelante, la lista de los archivos de un disco está contenida en un área del disco denominada “directorio”; por lo tanto, lo único que hay que hacer es leer dicho directorio. El lector de disquetes, por su parte, es un artilugio mecánico muy delicado y complejo; para acceder y manejar este dispositivo mecánico se dispone de procesadores especializados (denominados controladores) tales como el NEC PD765 utilizado en el PC de IBM.

Este controlador tiene 16 comandos, formado cada uno de ellos por una serie de 1 a 9 bytes que deben cargarse en uno de sus registros internos. Estos comandos sirven para leer y escribir datos, mover la cabeza de L/E, formatear las pistas, recalibrar los brazos con las cabezas de L/E, etc. Los comandos más básicos son READ y WRITE, cada uno de los cuales requiere 13 parámetros empaquetados en 9 bytes. Estos parámetros especifican datos tales como la dirección del bloque a leer, el número de sectores por pista, el modo de grabación de los datos, el interleaving y otras informaciones variadas. Cuando se completa una de las operaciones solicitadas mediante este controlador, éste devuelve uno entre 23 códigos de error o resultado de 7 bytes, códigos que se deben tratar convenientemente en caso de que se produzcan errores en la operación solicitada.

Además, en cada momento se debe estar pendiente de si el motor está arrancado o no, para encenderlo en caso necesario y con el tiempo de antelación debido. Por otra parte, el motor no debe estar constantemente encendido, pues de ser así, se desgastaría en poco tiempo.

No hace falta seguir profundizando sobre las acciones necesarias para efectuar con éxito la lectura del directorio de un disquete. Parece obvio que tales acciones no son nada triviales, o más aún, aunque alguno de los comandos que se utilizan para acceder al disquete no sean especialmente complicados, resultan, cuando menos, engorrosos de utilizar.

Pero entonces, para acceder a la información del disquete ¿tenemos que aprendernos el manual del NEC765?, ¿tenemos que ocuparnos personalmente de verificar y tratar adecuadamente los códigos de error que nos devuelve el controlador? Y si algún día se sustituye el controlador NEC PD765 por otro más eficiente ¿tenemos que aprendernos otra vez su funcionamiento?

La respuesta sería SÍ de no ser por la existencia del Sistema Operativo, pues una de sus funciones es la de actuar de interfaz entre al usuario y el hardware del ordenador. De esta manera, basta con indicarle mediante un comando lo que deseamos, para que él se encargue de arrancar, supervisar y controlar las operaciones necesarias con el hardware subyacente. Todo sin que nosotros tengamos que intervenir. Incluso si se da el caso de que el controlador correspondiente o cierto componente hardware es sustituido por otro, basta con modificar o sustituir la parte del sistema operativo que se encarga de la programación o manejo de tal dispositivo, de tal forma que el usuario no tiene ni por qué conocer el tipo concreto de los dispositivos que alberga su ordenador.

Como podemos ir viendo, el sistema operativo se encarga de esconder los entresijos del hardware del ordenador, ofreciendo una vista abstracta de sus componentes, y proporcionando los medios para manejarlos o acceder a ellos de una forma simple y sencilla.

El sistema operativo nos ofrece una máquina virtual distinta de la compuesta por los meros componentes hardware. Esta nueva máquina virtual nos ofrece los servicios normales que se desean de la máquina física que subyace, pero de tal forma que la utilización se realiza de una forma fácil, eficiente y adecuada.

Decimos que de una forma fácil porque nos proporciona servicios de alto nivel, al contrario de los que nos proporciona el controlador NEC PD765, que aunque son apropiados para su cometido (controlar el disquete) resultan insuficientes para obtener información tan simple como la lista de ficheros de un disquete. Esta insuficiencia se debe al hecho de que no basta con tener acceso al disquete, cosa que nos da el controlador, sino que además es necesario conocer la estructura de los datos del disquete para poder interpretarlos adecuadamente. El sistema operativo, además de ocuparse de programar el controlador, establece y conoce la estructura lógica de la información contenida en el disquete, siendo así capaz de ofrecer servicios de alto nivel.

Sabemos que los ordenadores nacieron siendo una ayuda extremadamente cara, por esto, el sistema operativo también debe encargarse de que los recursos físicos del sistema se aprovechen eficientemente, llevando la cuenta de su utilización y reparto entre múltiples programas o usuarios que deseen acceder a ellos. Así, por ejemplo, debe encargarse de repartir la memoria RAM de un sistema multiprogramado entre todas las aplicaciones en ejecución; de ir controlando el envío de listados a la impresora sin que se mezclen los de uno con los de otro usuario; o de ir repartiendo la CPU entre distintos programas para evitar tiempos muertos en su utilización.

Puesto que para aprovechar al máximo la utilización de los ordenadores se han inventado técnicas para compartir sus recursos entre varios usuarios, resulta indispensable introducir mecanismos para asegurar que el ordenador y sus recursos se utilizan adecuadamente, es decir, ofreciendo protección a los datos y programas de cada usuario de las posibles injerencias de los demás usuarios.

Hemos dicho anteriormente que el sistema operativo es la interfaz entre el usuario y el hardware del ordenador; ahora bien, el concepto usuario tiene un significado muy amplio en esta afirmación, es decir, que entendemos por usuario no solamente una persona sentada en la consola del sistema, sino también cualquier programa de aplicación invocado por alguna persona o programa, y que por supuesto, se ejecuta bajo la supervisión del sistema operativo.

Así pues, tenemos que el sistema operativo tiene interfaz, por una parte con los usuarios y los programas, y por otra parte con el hardware de la máquina. Los usuarios del sistema operativo pueden ser de cualquier índole: operadores, programadores de aplicaciones y de sistemas, administradores y, por supuesto, los propios usuarios finales de las aplicaciones.

El acceso al sistema operativo se realiza a través de las denominadas llamadas al sistema, que es un conjunto de servicios que proporciona de manera directa a cualquier aplicación. Para que las personas puedan acceder de forma directa al sistema operativo, se dispone de un programa especial denominado intérprete de comandos.

Este intérprete se encarga de recibir los comandos escritos en el teclado y pasárselos al sistema operativo mediante las correspondientes llamadas al sistema.

Históricamente el intérprete de comandos ha sido considerado como programa integrante del sistema operativo, sin embargo hoy día no hay un acuerdo al respecto. Tiempo atrás, cada sistema operativo ofrecía su propio intérprete de comandos, intérprete que estaba ligado de forma incuestionable al sistema operativo, debido a que estaba incluido en el núcleo o kernel del sistema. Hoy día, el intérprete de comandos no suele formar parte del núcleo del sistema operativo, de tal forma que es fácilmente substituible, pues no es más que un programa más realizando llamadas a los servicios del sistema operativo. De hecho, para sistemas operativos populares, como Unix, se suelen ofrecer distintos intérpretes de comandos como alternativas, lo cual da pie a que algunos autores no lo consideren como parte integrante del sistema operativo. No obstante, a pesar de la libertad para elegir o cambiar el intérprete de comandos, lo cierto es que todos los sistemas operativos de propósito general se ofrecen con un intérprete de comandos, suministrando incluso el correspondiente manual de uso como parte integrante del manual del sistema operativo completo. Y es que por el simple hecho de que se haya conseguido que algunas partes de los sistemas operativos sean fácilmente substituibles no tiene por que dar pie a pensar que por ello ya no forman parte de él.

Servicios del Sistema Operativo

Como hemos visto en el apartado anterior, el sistema operativo se comunica con los programas y con los usuarios, a quienes les ofrece sus servicios directamente. Pero el sistema operativo también ofrece otro tipo de servicios indirectos que aunque puede que el usuario no se aperciba de ellos, están dirigidos a mejorar la eficiencia y la seguridad del sistema. Podemos decir, entonces, que el sistema operativo ofrece servicios al usuario y al sistema.

Como sabemos, los usuarios directos del sistema son el programador, es decir, sus programas, y el operador, o sea, la persona que se comunica con el ordenador mediante un intérprete de comandos. Los programas utilizan los servicios del sistema operativo mediante las llamadas al sistema, esto es, un conjunto de rutinas de interfaz que ofrece el sistema operativo para solicitar sus servicios. En cualquier caso, de una u otra forma, tenemos que el sistema operativo ofrece básicamente estos servicios a los usuarios:

  • Ejecución de programas

    • El sistema le permite al usuario cargar y ejecutar programas, lo cual puede realizarlo bien desde el intérprete de comandos, o desde un programa en ejecución que realiza la apropiada llamada al sistema. Normalmente también facilita medios para controlar su ejecución, determinando en qué estadio se encuentra en cada momento o el tipo de operaciones que está realizando.

    • Asimismo, también proporciona, al final de la ejecución del programa, un código o resultado de la ejecución, indicando si ésta se realizó normalmente o surgió algún problema.

  • Operaciones con dispositivos de E/S.

    • En algún ejemplo anterior ya hemos visto lo dificultoso que puede resultar la interacción con los dispositivos del sistema, pues forman directamente la capa hardware, tan lejos de nosotros los humanos. Para aliviar esta farragosa interfaz, el sistema operativo nos ofrece una máquina virtual en la que los dispositivos de E/S se manejan mediante operaciones de muy alto nivel, que expresan directamente los servicios que una persona puede necesitar de estos periféricos, tales como rebobinar una cinta, formatear un disco, recibir o transmitir datos por una línea de comunicaciones, etc.

  • Manejo de ficheros

    • Si con las operaciones con los dispositivos de E/S se logra la abstracción del hardware, con el manejo de ficheros se consigue la independencia de la representación de las colecciones de datos, de tal forma que a una larga serie de bits se le puede tratar como un único objeto −un fichero de datos− despreocupándose de si los datos componentes del fichero ocupan un área consecutiva en el disco, o incluso de si está completamente contenida en un único disco o en varios. De esta manera se pueden realizar operaciones con un conjunto completo de datos tales como leer o escribir registros individuales, copiar ficheros, borrarlos, imprimirlos, visualizarlos por pantalla, buscar un registro dentro del fichero o simplemente pedir una lista de los ficheros de un disco.

En cuanto a los servicios ofrecidos al propio sistema, aunque estos son variados, pueden encuadrarse en dos grupos:

  • Gestión y contabilidad de recursos

  • Protección

A veces se oye hacer la comparación de que “un sistema operativo es como el gobierno de un país”, de tal forma que no solamente debe ofrecer servicios a los ciudadanos (los usuarios), sino que además debe preocuparse él mismo de su propia gestión para asegurar su buen funcionamiento. Para ello, debe llevar la cuenta de los recursos de que dispone, de los que están disponibles, de los que están ocupados y de quién los tiene en uso, bien sea para repartirlos de la manera adecuada y justa, bien sea para pasar factura posteriormente, o simplemente para poder reclamarlos cuando estime que algo anormal sucede con ellos y puedan haberse perdido. Los recursos básicos gestionados son los componentes hardware del ordenador:

  • La CPU

  • La Memoria

  • Los dispositivos de E/S

Con una acertada gestión del procesador se consigue un buen rendimiento del ordenador, como es el caso de los sistemas multiprogramados o multiusuarios. Una persona que está sentada en un terminal de un ordenador multiusuario puede que no sea consciente de si el ordenador es multiusuario o no, ni le preocupa; desde su punto de vista él tiene una máquina dedicada. Como vemos, este es un servicio que no es directamente visible por los usuarios, pero que ayuda a aprovechar la utilización del sistema.

Mediante ciertos algoritmos de gestión de memoria, al usuario se le pueden proporcionar servicios tales como la Memoria Virtual, mediante el cual el usuario tiene la posibilidad de ejecutar programas más grandes que la memoria principal disponible. El usuario simplemente piensa que siempre dispone de “mucha memoria”. El sistema operativo también debe ocuparse de repartir la memoria entre todos los programas en ejecución.

También debe llevar control de los periféricos, como por ejemplo de las impresoras, discos o armarios de cinta, de tal forma que cuando un programa solicite la impresión de un fichero o la carga de una cinta en un cierto armario, el sistema operativo sepa asignar un dispositivo libre o poner en la cola de espera al proceso peticionario.

Al igual que los servicios internos de espionaje se preocupan de la seguridad dentro de los órganos de gobierno de la nación, en un sistema operativo se deben tomar las medidas oportunas para evitar que algún programa o usuario, voluntaria o inadvertidamente realice alguna operación que ponga en peligro la integridad del sistema, tanto de los programas y datos componentes del sistema operativo como del resto de los usuarios del sistema. Dado que las operaciones de bajo nivel permiten realizar cualquier acción con la máquina, el sistema operativo esconde estas operaciones que ofrece el hardware impidiendo el acceso a ellas, y ofreciendo en su lugar otras operaciones y servicios que, además de ser de más alto nivel, no incluyen la posibilidad de realizar operaciones o acciones peligrosas, tanto para el propio proceso y demás usuarios (por ejemplo, borrar ficheros de otros usuarios), como para el propio sistema operativo (formatear el disco duro).

Llamadas al Sistema

Las llamadas al sistema son el conjunto de servicios que ofrece el sistema operativo al nivel de programación, o lo que es lo mismo, componen la interfaz de programación del sistema operativo.

Los servicios clásicos que ofrecen las llamadas al sistema están enfocados al control y ejecución de programas, al control de recursos (ficheros y dispositivos de E/S) y a proporcionar información del propio proceso y del sistema.

Y ¿cómo es el mecanismo de las llamadas al sistema? Pues si estos servicios son accesibles desde los programas, lo natural es que se ofrezcan como un conjunto de rutinas o subprogramas a los que se puede llamar de una manera sencilla y con los parámetros indispensables para cada servicio. Aunque la llamada al sistema operativo siempre la puede realizar directamente el usuario en lenguaje ensamblador, todos los sistemas operativos proporcionan rutinas de interfaz para lenguajes de alto nivel, como C, Pascal, Ada, FORTRAN, etc., dependiendo de cada sistema. Así, para abrir un fichero se suele disponer de una rutina para llamar desde C, otra para llamar desde Pascal, quizás otra para llamar desde FORTRAN, etc. Y todas ellas realizan la misma acción: preparar los parámetros en el formato adecuado y pasárselos al sistema operativo según el método adoptado.

Hay tres métodos básicos para pasar los parámetros al sistema operativo desde las rutinas de interfaz: 1) Lo más simple consiste en pasar los parámetros en los registros generales del procesador; pero en algunos casos puede que haya más parámetros que registros, en cuyo caso lo que se hace es 2) agrupar los parámetros en un bloque (un registro de los de Pascal) y pasar la dirección del bloque en uno de los registros generales. 3) Otra posibilidad consiste en poner los parámetros en la pila del proceso y ceder el control al sistema operativo, el cual se ocupa de sacar los parámetros de la pila. Este último método tiene la ventaja de no tener límite ni en el tamaño ni el número de los parámetros. También se pueden encontrar sistemas con mezclas de los modelos 1 y 3.

En la parte inferior de la Figura 15 se puede ver un fragmento de un programa de usuario escrito en Pascal. En él se realiza una llamada al sistema para leer un dato del disco: Leer_Disco. Así, se deben suministrar tres parámetros: El nombre del fichero, la dirección del buffer donde deberá dejar el sistema operativo el dato solicitado, y el número de bytes a leer, es decir, la longitud del dato. A la derecha tenemos la rutina de interfaz Leer_Disco. Como vemos, ésta se limita a pasar la información adecuada siguiendo el protocolo de comunicación con el sistema operativo, o sea, pone el código de operación correspondiente a una lectura de disco en el registro general R1, y a continuación mete en la pila los tres parámetros recibidos del programa llamante. Por último genera la interrupción software 3 para dar control al sistema operativo.

Cuando éste recibe el control desde una interrupción 3, sabe que se le está solicitando un servicio del usuario, por lo que averigua cuál es el servicio analizando el contenido del registro R1. Una vez conocido el servicio y habiendo sacado de la pila los parámetros correspondientes, realiza la operación solicitada.

En la Figura 16 tenemos el esquema de una secuencia completa de la llamada y ejecución de una llamada al sistema. Aunque hay diversos protocolos de comunicación o cesión de control al sistema operativo, aquí se muestra uno de los más habituales, el realizado mediante una trap o interrupción software.

Las llamadas al sistema varían en número y semántica de unos sistemas operativos a otros, pues además de tener distintos diseños, pueden disponer de distintos componentes hardware que limitan o amplían los servicios del sistema operativo.

Por último, podemos decir que es deseable que el conjunto de llamadas al sistema ofrecidas no sean redundantes, para mantener una interfaz simple, aunque sí debe ser completo, para ofrecer todos los servicios disponibles del sistema operativo.

Comments