Logo Studenta

Silberschatz 10a castellano cap12

¡Este material tiene más páginas!

Vista previa del material en texto

CAPÍTULO 12
Sistemas de E/S
Los dos trabajos principales de una computadora son la E/S y la computación. En muchos casos, el trabajo principal es la E/S, y la computación o el procesamiento es meramente incidental. Por ejemplo, cuando navegamos por una página web o editamos un archivo, nuestro interés inmediato es leer o ingresar alguna información, no calcular una respuesta.
La función del sistema operativo en la E/S de la computadora es administrar y controlar las operaciones de E/S y dispositivos de E/S. Aunque los temas relacionados aparecen en otros capítulos, aquí reunimos las piezas para mostrar una imagen completa de E/S. Primero, describimos los conceptos básicos del hardware de E/S, porque la naturaleza de la interfaz de hardware impone restricciones a las instalaciones internas del sistema operativo. A continuación, discutimos los servicios de E/S proporcionados por el sistema operativo y la realización de estos servicios en la interfaz de E/S de la aplicación. Luego, explicamos cómo el sistema operativo cierra la brecha entre el hardware interfaz y la interfaz de la aplicación. También discutimos el Sistema V de UNIX Mecanismo STREAMS, que permite a una aplicación ensamblar tuberías del código del controlador de forma dinámica. Finalmente, discutimos los aspectos de rendimiento de E/S y los principios del diseño del sistema operativo que mejoran el rendimiento de E/S.
OBJETIVOS DEL CAPÍTULO
• Explore la estructura del subsistema de E/S de un sistema operativo.
• Analizar los principios y complejidades del hardware de E/S.
• Explicar los aspectos de rendimiento del hardware y software de E/S.
12.1 Antecedentes
El control de los dispositivos conectados a la computadora es una de las principales preocupaciones de diseñadores de sistemas operativos. Porque los dispositivos de E/S varían mucho en su función y velocidad (considere un mouse, un disco duro, una unidad flash y una cinta robot), se necesitan métodos variados para controlarlos. Estos métodos forman el Subsistema de E/S del kernel, que separa el resto del kernel de las complejidades de la gestión de dispositivos de E/S. Ver una creciente estandarización de las interfaces de software y hardware. Esta tendencia nos ayuda a incorporar generaciones mejoradas de dispositivos en las computadoras existentes y sistemas operativos Por otro lado, vemos una variedad cada vez más amplia de dispositivos de E/S. Algunos dispositivos nuevos son tan diferentes a los dispositivos anteriores que es un desafío para incorporarlos a nuestras computadoras y sistemas operativos. Este desafío se resuelve mediante una combinación de técnicas de hardware y software. Los elementos básicos de hardware de E/S, como puertos, buses y controladores de dispositivos, acomodarlos para una amplia variedad de dispositivos de E/S. Para encapsular los detalles y rarezas de diferentes dispositivos, el kernel de un sistema operativo está estructurado para utilizar módulos de controlador de dispositivo. Los controladores de dispositivo presentan un acceso de interfaz uniforme de dispositivos al subsistema de E/S, tanto como las llamadas al sistema proporcionan una interfaz estándar entre la aplicación y el sistema operativo.
12.2 Hardware de E/S
Las computadoras operan una gran variedad de dispositivos. La mayoría encaja en la categoría general de dispositivos de almacenamiento (discos, cintas), dispositivos de transmisión (conexiones de red, Bluetooth) y dispositivos de interfaz humana (pantalla, teclado, mouse, entrada y salida de audio). Otros dispositivos son más especializados, como los involucrados en la dirección de un jet. En estos aviones, un humano da entrada a la computadora de vuelo a través de un joystick y pedales, y la computadora envía comandos de salida que hacen que los motores muevan timones y flaps y combustible a los motores. A pesar de la increíble variedad de dispositivos de E/S, sin embargo, sólo necesitamos algunos conceptos para comprender cómo se conectan los dispositivos y cómo el software puede controlar el hardware.
Un dispositivo se comunica con un sistema de computación enviando señales por un cable o incluso a través del aire. El dispositivo se comunica con la máquina a través de un punto de conexión o puerto, por ejemplo, un puerto serie. (El término PHY, abreviatura de la capa física del modelo OSI, también se utiliza en referencia a los puertos, pero es más común en la nomenclatura de los centros de datos). Si los dispositivos comparten un conjunto de cables, la conexión se llama bus. Un bus, como el bus PCI utilizado en la mayoría computadoras hoy en día, es un conjunto de cables y un protocolo rígidamente definido que especifica un conjunto de mensajes que se pueden enviar por cable. En cuanto a la electrónica, los mensajes se transmiten mediante patrones de voltajes eléctricos aplicados a los cables. con tiempos definidos. Cuando el dispositivo A tiene un cable que se conecta al dispositivo B, y El dispositivo B tiene un cable que se conecta al dispositivo C, y el dispositivo C se conecta a un puerto en la computadora, esta disposición se llama cadena tipo margarita. Una cadena de margaritas generalmente funciona como un bus.
Los buses se utilizan ampliamente en la arquitectura de computadoras y varían en su señalización, métodos, velocidad, rendimiento y métodos de conexión. La estructura de un bus de PC típico aparece en la Figura 12.1. 
Figura 12.1 Una estructura de bus de PC típica
En la figura, un bus PCIe (el bus del sistema más común de una PC) conecta el subsistema procesador-memoria a dispositivos rápidos, y un bus de expansión conecta dispositivos relativamente lentos, como el teclado y puertos seriales y USB. En la parte inferior izquierda de la figura, se muestran cuatro discos. conectados juntos en un bus SCSI conectado en serie (SAS) conectado a un SAS controlador. PCIe es un bus flexible que envía datos a través de uno o más "carriles" (lanes). Un carril se compone de dos pares de señalización, un par para recibir datos y el otro para transmitir. Por lo tanto, cada carril se compone de cuatro cables, y cada el carril se utiliza como un flujo de bytes full-duplex, transportando paquetes de datos en formato de ocho bits (byte) simultáneamente en ambas direcciones. Físicamente, los enlaces PCIe pueden contener 1, 2, 4, 8, 12, 16 o 32 carriles, como lo indica el prefijo "x". Una Tarjeta PCIe o el conector que usa 8 carriles se designa x8, por ejemplo. Además, PCIe ha pasado por múltiples "generaciones", y habrá más en el futuro. Así, por ejemplo, una tarjeta puede ser "PCIe gen3 x8", lo que significa que funciona con generación 3 de PCIe y utiliza 8 carriles. Tal dispositivo tiene un rendimiento máximo de 8 gigabits por segundo. Los detalles sobre PCIe se pueden encontrar en https://pcisig.com. Un controlador es una colección de componentes electrónicos que pueden operar un puerto, un bus o un dispositivo. Un controlador de puerto serie es un controlador de dispositivo simple. Es un solo chip (o parte de un chip) en la computadora que controla las señales en los cables de un puerto serie. Por el contrario, un controlador de bus de canal de fibra (FC) no es sencillo. Debido a que el protocolo FC es complejo y se usa en centros de datos en lugar de en PC, el controlador de bus FC se implementa a menudo como una placa de circuito separada —O un adaptador de bus de host (HBA) —que se conecta a un bus en la computadora. Eso normalmente contiene un procesador, microcódigo y algo de memoria privada para permitir para procesar los mensajes del protocolo FC. Algunos dispositivos tienen su propio controlador. Si observa una unidad de disco, verá una placa de circuito adjunta a un lado. Esta placa es el controlador de disco. Implementa del lado del disco el protocolo para algunos tipos de conexión, SAS y SATA, por ejemplo. Tiene microcódigo y un procesador para realizar muchas tareas, como mapeo de sectores defectuosos, búsqueda previa, almacenamiento en búfer y almacenamiento en caché. 
12.2.1 E/S mapeadas en memoria
¿Cómo da elprocesador comandos y datos a un controlador para lograr una transferencia de E/S? La respuesta corta es que el controlador tiene uno o más registros para señales de datos y control. El procesador se comunica con el controlador leyendo y escribiendo patrones de bits en estos registros. Una forma en la que esta comunicación puede ocurrir mediante el uso de instrucciones de E/S especiales que especifican la transferencia de un byte o una palabra a una dirección de puerto de E/S. 
Figura 12.2 Ubicaciones de los puertos de E/S del dispositivo en las PC (parcial).
La instrucción de E/S activa las líneas de bus para seleccionar el dispositivo adecuado y mueve bits hacia o desde de un registro de dispositivo. Como alternativa, el dispositivo puede admitir E/S mapeada en memoria. En este caso, los registros de control de dispositivos se asignan a la dirección espacio del procesador como si fueran registros de memoria. Entonces la CPU ejecuta solicitudes de E/S utilizando la transferencia de datos estándar se hará con instrucciones para leer (load) o escribir (store) los registros de control de dispositivos en ubicaciones mapeadas en la memoria física. En el pasado, las PC solían usar instrucciones de E/S para controlar algunos dispositivos y E/S mapeadas en memoria para controlar a otros. La figura 12.2 muestra las direcciones de puerto de E/S habitual para una PC. El controlador de gráficos tiene puertos de E/S para control básico de operaciones, pero el controlador tiene una gran región mapeada en memoria para contener el contenido de la pantalla. Un hilo envía la salida a la pantalla escribiendo datos en la región mapeada en memoria. El controlador genera la imagen de la pantalla basada sobre el contenido de esta memoria. Esta técnica es sencilla de utilizar. Además, escribir millones de bytes en la memoria gráfica es más rápido que emitir millones de instrucciones de E/S. Por lo tanto, con el tiempo, los sistemas se han movido hacia E/S mapeadas en memoria. Hoy en día, la mayoría de las E/S se realizan mediante controladores de dispositivos y mediante E/S mapeadas en memoria.
El control del dispositivo de E/S generalmente consta de cuatro registros, llamados estado, registros de control, entrada y salida de datos.
• El host lee el registro de entrada de datos para obtener la entrada.
• El host escribe el registro de salida de datos para enviar la salida.
• El registro de estado contiene bits que puede leer la CPU. Estos bits indican estados, como cuando el comando actual se ha completado, si un byte está disponible para ser leído desde el registro de entrada de datos, y si ha ocurrido un error de dispositivo.
• El host (CPU) puede escribir el registro de control para iniciar un comando o para cambiar el modo de un dispositivo. Por ejemplo, cierta parte del control del registro de un puerto serie elige entre comunicación full-duplex o half-duplex, otro bit habilita la verificación de paridad, un tercer bit establece la palabra longitud a 7 u 8 bits, y otros bits seleccionan una de las velocidades admitidas por el puerto serie.
Los registros de datos suelen tener un tamaño de 1 a 4 bytes. Algunos controladores tienen Chips FIFO que pueden contener varios bytes de datos de entrada o salida para expandir la capacidad del controlador más allá del tamaño del registro de datos. Un chip FIFO puede mantener una pequeña ráfaga de datos hasta que el dispositivo o el host pueda recibir esos datos.
12.2.2 Sondeo (Polling)
El protocolo completo para la interacción entre el host y un controlador puede ser intrincado, pero la noción básica de apretón de manos (handshaking) es simple. Explicamos el apretón de manos con un ejemplo. Suponga que se utilizan 2 bits para coordinar la relación productor-consumidor entre el controlador y la CPU. El controlador indica su estado a través del bit de ocupado en el registro de estado. (Recordar, que establecer un bit significa escribir un 1 en el bit y borrar un bit significa escribir un 0 en él.) El controlador establece el bit de ocupado cuando está ocupado trabajando y borra el bit de ocupado cuando está listo para aceptar el siguiente comando. El anfitrión (CPU) señala su deseo a través del bit de comando (ready) listo en el registro de comando. El anfitrión establece el bit de comando listo cuando hay un comando disponible para que el controlador lo ejecute.
Para este ejemplo, el host escribe la salida a través de un puerto, coordinándose con el controlador mediante protocolo de handshaking de la siguiente manera:
1. El host lee repetidamente el bit de ocupado hasta que ese bit se aclara (borra).
2. El host establece el bit de escritura en el registro de comando y escribe un byte en el registro de salida de datos.
3. El host establece el bit de comando listo.
4. Cuando el controlador ve que el bit de comando está listo (ready) está establecido, establece el bit en ocupado.
5. El controlador lee el registro de comando y ve el comando de escritura. Lee el registro de salida de datos para obtener el byte y realiza la S al dispositivo.
6. El controlador borra el bit de comando listo, borra el bit de error en el registro de estado para indicar que la E/S del dispositivo se realizó correctamente y borra el bit de ocupado para indicar que ha terminado.
Este bucle se repite para cada byte. En el paso 1, el host está ocupado esperando o sondeando: está en un bucle, leyendo el registro de estado una y otra vez hasta que se borre el bit de ocupado. Si el controlador y el dispositivo son rápidos, este método es razonable. Pero si la espera puede ser larga, el anfitrión probablemente debería cambiar a otra tarea. Entonces, ¿cómo sabe el anfitrión cuando el controlador está inactivo? Para algunos dispositivos, el host debe dar servicio al dispositivo rápidamente, o se perderán los datos. Por ejemplo, cuando se transmiten datos en un puerto serie o desde un teclado, el pequeño búfer en el controlador desbordamiento y los datos se perderán si el host espera demasiado antes de volver a leer los bytes.
En muchas arquitecturas de computadora, tres ciclos de instrucción de CPU son suficientes para sondear un dispositivo: leer un registro de dispositivo, la lógica y extracción de un bit de estado, y bifurcar si no es cero. Claramente, la operación de sondeo básica es eficiente. Pero el sondeo se vuelve ineficaz cuando se intenta repetidamente, pero rara vez encuentra un dispositivo listo para el servicio, mientras que otros procesamientos útiles de la CPU permanecen sin hacer. En tales casos, puede ser más eficiente disponer que el controlador de hardware para notificar a la CPU cuando el dispositivo esté listo para el servicio, en lugar de para requerir que la CPU sondee repetidamente para completar la E/S. El hardware El mecanismo que permite que un dispositivo notifique a la CPU se denomina interrupción.
12.2.3 Interrupciones
El mecanismo de interrupción básico funciona de la siguiente manera. El hardware de la CPU tiene cable llamado la línea de solicitud de interrupción que la CPU detecta después de ejecutar cada instrucción. Cuando la CPU detecta que un controlador ha afirmado una señal en la línea de solicitud de interrupción, la CPU realiza un guardado del estado y salta a la rutina del manejador de interrupciones en una dirección fija en la memoria. El manejador de interrupciones determina la causa de la interrupción, realiza el procesamiento necesario, realiza una restauración del estado y ejecuta un retorno de la instrucción de interrupción para devolver la CPU al estado de ejecución antes de la interrupción. Nosotros decimos eso: el controlador de dispositivo genera una señal de interrupción en la línea de solicitud de interrupción. Luego la CPU detecta la interrupción y la envía al (interrupt handler) manejador de interrupciones, y el handler borra la interrupción dando servicio al dispositivo La Figura 12.3 resume el ciclo de E/S controlado por interrupciones.
Figura 12.3 Ciclo de E/S controlado por interrupción.
Figura 12.4 Comando de latencia en Mac OS X.
Enfatizamos la gestiónde interrupciones en este capítulo porque incluso un sistema moderno de solo un usuario, gestionan cientos de interrupciones por segundo y los servidores cientos de miles por segundo. Por ejemplo, la Figura 12.4 muestra la salida de la latencia de un comando en un macOS, lo que revela que durante diez segundos un escritorio silencioso computadora realizó casi 23.000 interrupciones.
El mecanismo de interrupción básico que se acaba de describir permite a la CPU responder a un evento asincrónico, como cuando un controlador de dispositivo está listo para el servicio. En un sistema operativo moderno, sin embargo, necesitamos un manejo de interrupciones con características más sofisticadas.
1. Necesitamos la capacidad de diferir el manejo de interrupciones durante el procesamiento crítico.
2. Necesitamos una forma eficiente de enviar al controlador de interrupciones adecuado para un dispositivo sin primero sondear todos los dispositivos para ver cuál levantó la interrupción.
3. Necesitamos interrupciones multinivel, para que el sistema operativo pueda distinguir entre interrupciones de alta y baja prioridad y puede responder con el grado apropiado de urgencia cuando hay múltiples concurrentes interrumpe.
4. Necesitamos una forma de que una instrucción llame la atención del sistema operativo. directamente (por separado de las solicitudes de E/S), para actividades como la página fallas y errores como división por cero. Como veremos, esta tarea es logrado por "trampas" (TRAP).
En el hardware de computación moderno, estas características las proporciona la CPU y el hardware del controlador de interrupciones. La mayoría de las CPU tienen dos líneas de solicitud de interrupción. Una es una interrupción no enmascarable, que está reservada para eventos como errores de memoria irrecuperables.
La segunda línea de interrupción es enmascarable: la CPU puede apagarla antes la ejecución de secuencias de instrucciones críticas que no deben interrumpirse. 
Los controladores de dispositivos utilizan la interrupción enmascarable para solicitar servicio. El mecanismo de interrupción acepta una dirección, un número que selecciona una rutina específica de manejo de interrupciones de un pequeño conjunto. En la mayoría de las arquitecturas, esta dirección es un desplazamiento en una tabla llamada vector de interrupción. Este vector contiene las direcciones de memoria de los manejadores de interrupciones especializados. El propósito de un mecanismo de interrupción vectorial es reducir la necesidad de una sola interrupción manejador y buscar todas las posibles fuentes de interrupciones para determinar cuál necesita servicio. En la práctica, sin embargo, las computadoras tienen más dispositivos (y, por lo tanto, manejadores de interrupciones) que tienen más elementos de dirección que el vector de interrupción.
Una forma común de resolver este problema es utilizar el encadenamiento de interrupciones, en el que cada elemento en el vector de interrupción apunta al encabezado de una lista de manejadores de interrupciones. Cuando se genera una interrupción, los controladores de la lista correspondiente se revisan uno por uno, hasta que se encuentra uno que pueda atender la solicitud. Esta estructura es un compromiso entre la sobrecarga de una enorme tabla de interrupciones y la ineficacia de enviar a un solo controlador de interrupciones.
La figura 12.5 ilustra el diseño del vector de interrupción para Intel Pentium procesador. Los eventos de 0 a 31, que no se pueden enmascarar, se utilizan para señalar varias condiciones de error (que causan fallas del sistema), fallas de página (que necesita una acción inmediata) y solicitudes de depuración (detener el funcionamiento normal y saltar a una aplicación de depuración). Los eventos del 32 al 255, que son enmascarables, se utilizan para fines tales como interrupciones generadas por dispositivos 
Figura 12.5 Tabla de vectores de eventos del procesador Intel Pentium.
El mecanismo de interrupción también implementa un sistema de prioridad de interrupción en niveles. Estos niveles permiten a la CPU diferir el manejo de interrupciones de baja prioridad sin enmascarar todas las interrupciones y hacen posible que una interrupción de alta prioridad pueda adelantarse a la ejecución de una interrupción de baja prioridad.
Un sistema operativo moderno interactúa con el mecanismo de interrupción en varias formas. En el momento del arranque, el sistema operativo prueba los buses de hardware para determinar qué dispositivos están presentes e instalar los correspondientes manejadores de interrupción en el vector de interrupción. Durante la E/S, los distintos controladores de dispositivos generan interrupciones cuando estén listas para el servicio. Estas interrupciones significan que la salida se ha completado, o que los datos de entrada están disponibles, o que ha sido detectado. El mecanismo de interrupción también se utiliza para manejar una amplia variedad de excepciones, como dividir por cero, acceder a un sitio protegido o inexistente dirección de memoria, o intentar ejecutar una instrucción privilegiada desde modo de usuario. Los eventos que desencadenan interrupciones tienen una propiedad común: son sucesos que inducen al sistema operativo a ejecutar una rutina urgente e independiente.
Porque manejar la interrupción en muchos casos requiere tiempo y recursos limitados y por lo tanto complicados de implementar, los sistemas frecuentemente se dividen entre la gestión de un controlador de interrupciones de primer nivel (FLIH) y un segundo nivel manejador de interrupciones (SLIH). El FLIH realiza el cambio de contexto, almacenamiento de estado, y puesta en cola de una operación del manejador, mientras que el SLIH, planificado por separado, realiza el manejo de la operación solicitada.
Los sistemas operativos también hacen otros usos de las interrupciones. Por ejemplo, muchos sistemas operativos utilizan el mecanismo de interrupción para la paginación en memoria virtual. Una falla de página es una excepción que genera una interrupción. La interrupción suspende el proceso actual y salta al manejador de fallas de página en el kernel. Este manejador guarda el estado del proceso, mueve el proceso a la cola de espera, realiza la administración de la caché de página, planifica una operación de E/S para recuperar la página, planifica otro proceso para reanudar la ejecución y luego regresa de la interrupción.
Otro ejemplo se encuentra en la implementación de llamadas al sistema. Por lo general, un programa utiliza llamadas a la biblioteca para emitir llamadas al sistema. Las rutinas de la biblioteca comprueban argumentos dados por la aplicación, construyen una estructura de datos para transmitir los argumentos al kernel y luego ejecuta una instrucción especial llamada interrupción de software o TRAP. Esta instrucción tiene un operando que identifica el servicio deseado del kernel. Cuando un proceso ejecute la instrucción trap, el hardware de interrupción guarda el estado del código de usuario, cambia al modo kernel y deriva al hilo o a la rutina del kernel o que implementa el servicio solicitado. La trampa tiene una prioridad de interrupción relativamente baja en comparación con las asignadas a interrupciones del dispositivo: ejecutar una llamada al sistema en nombre de una aplicación es menos urgente que dar servicio a un controlador de dispositivo antes de que su cola FIFO se desborde y pierda datos.
Las interrupciones también se pueden usar para administrar el control de flujo dentro del kernel. Por ejemplo, considere el caso del procesamiento requerido para completar una lectura de disco. Un paso puede ser copiar datos del espacio del kernel al búfer del usuario. Esta copia lleva mucho tiempo, pero no es urgente; no debe bloquear otros elementos de alta prioridad interrumpir el manejo. Otro paso es iniciar la siguiente E/S pendiente para esa unidad de disco. Este paso tiene mayor prioridad. Si los discos se van a utilizar de forma eficiente, necesitamos iniciar la siguiente E/S tan pronto como se completela anterior. En consecuencia, un par de manejadores de interrupciones implementan el código del kernel que completa una lectura de disco. El controlador de alta prioridad registra el estado de E/S, limpia la interrupción del dispositivo, inicia la siguiente E/S pendiente y eleva una interrupción de prioridad baja y completa el trabajo. Más tarde, cuando la CPU no está ocupada con trabajo de alta prioridad, se ejecutará la interrupción de baja prioridad. El correspondiente controlador completa la E/S a nivel de usuario copiando los datos de los búferes del kernel al espacio de la aplicación y luego llamar al planificador para colocar la aplicación en la cola de listos.
Una arquitectura de kernel con hilos es adecuada para implementar múltiples prioridades de interrupciones y para hacer cumplir la precedencia del manejo de interrupciones sobre el fondo procesamiento en rutinas de kernel y aplicación. Ilustramos este punto con el kernel de Solaris. En Solaris, los manejadores de interrupciones se ejecutan como hilos de kernel. Se reserva una variedad de prioridades altas de planificación para estos hilos. Estos valores dan prioridad a los manejadores de interrupciones sobre el código de la aplicación y mantenimiento del kernel e implementan las relaciones de prioridad entre los manejadores de interrupciones. Las prioridades hacen que el planificador de hilos de Solaris expulse a los manejadores de interrupción de prioridad más baja en favor de los de mayor prioridad, y la implementación multihilada permite que el hardware multiprocesador ejecute varios manejadores de interrupciones. al mismo tiempo. Describimos la arquitectura de interrupciones de Linux en el capítulo 20, Windows10 en el Capítulo 21 y UNIX en el Apéndice C.
En resumen, las interrupciones se utilizan en todos los sistemas operativos modernos para manejar eventos asincrónicos y capturar rutinas en modo supervisor en el kernel. Para permitir que el trabajo más urgente se realice primero, las computadoras modernas utilizan un sistema de prioridades de interrupción. Controladores de dispositivos, fallas de hardware y todas las llamadas del sistema aumentan las interrupciones para activar las rutinas del kernel. Porque las interrupciones se utilizan mucho para procesamiento urgente,el manejo eficiente de interrupciones es necesario para un buen rendimiento del sistema. La E/S impulsada por interrupciones ahora es mucho más común que el sondeo, y el sondeo se utiliza para E/S de alto rendimiento.
A veces, los dos se usan juntos. Algunos controladores de dispositivos utilizan interrupciones cuando la tasa de E/S es baja y cambia a sondeo cuando la tasa aumenta hasta el punto donde el sondeo es más rápido y eficiente.
12.2.4 Acceso directo a memoria
Para un dispositivo que realiza grandes transferencias, como una unidad de disco, parece un desperdicio utilizar un costoso procesador de propósito general para ver los bits de estado y para alimentar datos en un registro del controlador un byte a la vez, un proceso así se denomina E/S programadas (PIO). Las computadoras evitan sobrecargar la CPU principal con PIO al descargar parte de este trabajo a un procesador de propósito especial llamado controlador de acceso directo a memoria (DMA). Para iniciar una transferencia DMA, el host escribe un Bloque de comando en la memoria de DMA. Este bloque contiene un puntero a la fuente de una transferencia, un puntero al destino de la transferencia y un contador del número de bytes a transferir. Un bloque de comando puede ser más complejo, incluyendo una lista de direcciones de origen y destino que no son contiguas. Este método de dispersión y recopilación (direcciones vectorizadas) permite que se ejecuten varias transferencias a través de una único Comando DMA. La CPU escribe la dirección de este bloque de comando en el Controlador DMA, luego continúa con otros trabajos. El controlador DMA procede para operar con el bus de memoria directamente, colocando direcciones en el bus para realizar transferencias sin la ayuda de la CPU principal. Un controlador DMA simple es un componente estándar en todas las computadoras modernas, desde teléfonos inteligentes hasta computación centralizada (mainframe)
Tenga en cuenta que es más sencillo que la dirección de destino esté en el espacio de dirección del kernel. Si estuviera en el espacio de usuario, el usuario podría, por ejemplo, modificar el contenido de ese espacio durante la transferencia, perdiendo algún conjunto de datos. Para obtener los Datos transferidos por DMA al espacio de usuario para que acceda el hilo, Se necesita una segunda operación de copia, esta vez de la memoria del kernel a la memoria del usuario. Este doble búfer es ineficaz. Con el tiempo, los sistemas operativos han mejorado al utilizar el mapeo de memoria (consulte la Sección 12.2.1) para realizar transferencias de E/S directamente entre el espacio de los dispositivos y de las direcciones del usuario.
El protocolo handshaking entre la controladora DMA y la controladora del dispositivo se realiza a través de un par de cables denominados solicitud DMA y reconocimiento DMA. La controladora del dispositivo coloca una señal en el cable de solicitud DMA cuando una palabra de datos está disponible para su transferencia. Esta señal hace que la controladora DMA tome el control del bus de memoria, coloque la dirección deseada en el cable de dirección de memoria y coloque una señal en el cable de reconocimiento DMA Cuando la controladora del dispositivo recibe la Señal de reconocimiento DMA, transfiere la palabra de datos a la memoria y borra la señal de solicitud de DMA.
Cuando finaliza toda la transferencia, la controladora DMA interrumpe la CPU. Esta secuencia se muestra en la Figura 12.6. Cuando la controladora DMA toma el bus de memoria, la CPU no puede acceder momentáneamente a la memoria principal, aunque todavía puede acceder a elementos de datos en sus cachés. Aunque este robo de ciclo puede ralentizar el cálculo de la CPU, descargando la transferencia de datos trabajar con un controlador DMA generalmente mejora el rendimiento total del sistema. Algunas arquitecturas de computadora usan direcciones de memoria física para DMA, pero otros realizan acceso directo a memoria virtual (DVMA), utilizando direcciones virtuales que deben ser traducidas a direcciones físicas. DVMA puede realizar una transferencia entre dos dispositivos mapeados en memoria sin la intervención de la CPU o el uso de la memoria principal.
Figura 12.6 Pasos en una transferencia DMA
En los kernels de modo protegido, el sistema operativo generalmente evita que los procesos emitan comandos de dispositivo directamente. Esta disciplina protege a los datos de violaciones de control de acceso y también protege el sistema de un uso erróneo de drivers (manejadores) de dispositivos, lo que podría provocar un bloqueo del sistema. En cambio, el sistema operativo exporta funciones que un proceso suficientemente privilegiado puede utilizar para acceder a operaciones de bajo nivel en el hardware subyacente. En kernels sin protección de memoria, los procesos pueden acceder directamente a los controladores de dispositivos. Este acceso directo se puede utilizar para lograr un alto rendimiento, ya que puede evitar la intervención del kernel, los cambios de contexto y las capas de software del kernel. Desafortunadamente, interfiere con la seguridad y estabilidad del sistema. Normalmente los sistemas operativos de propósito general protegen la memoria y los dispositivos para que el sistema pueda intentar protegerse contra aplicaciones erróneas o maliciosas.
12.2.5 Resumen de hardware de E/S
Aunque los aspectos de hardware de E/S son complejos cuando se consideran en el nivel de detalle del diseño de hardware electrónico, los conceptos que acabamos de describir son suficientes para permitirnos comprender muchas características de E/S de los sistemas operativos. Repasemos los conceptos principales:
• Un Bus
• Una placa controladora
• Un puerto de E/S y sus registros
• La relación de apretón demanos (handshaking) entre el host y una controladora de dispositivo
• La ejecución de este protocolo de enlace en un bucle de sondeo o mediante interrupciones
• La descarga de este trabajo a un controlador DMA para grandes transferencias
Dimos un ejemplo básico del apretón de manos que tiene lugar entre una controladora de dispositivo y el host anteriormente en esta sección. En realidad, la amplia variedad de dispositivos disponibles plantea un problema para los implementadores de sistemas operativos. Cada tipo de dispositivo tiene su propio conjunto de capacidades, definiciones de bits de control y protocolos para interactuar con el anfitrión, y todos son diferentes. ¿Cómo puede el sistema operativo estar diseñado para que podamos conectar nuevos dispositivos a la computadora sin reescribir el sistema operativo? Y cuando los dispositivos varían tanto ¿Cómo puede el sistema operativo ofrecer una interfaz de E/S uniforme y conveniente? a las aplicaciones? A continuación, abordamos esas preguntas.
12.3 Interfaz de E/S de la aplicación
En esta sección, discutimos técnicas de estructuración e interfaces para el sistema operativo que permite tratar los dispositivos de E/S de forma estándar y uniforme. Explicamos, por ejemplo, cómo una aplicación puede abrir un archivo en un disco sin saber qué tipo de disco es y cómo los nuevos discos y otros dispositivos pueden ser agregados a una computadora sin interrumpir el sistema operativo.
Al igual que otros problemas complejos de ingeniería de software, el enfoque aquí implica abstracción, encapsulación y capas de software. Específicamente, podemos abstraer las diferencias de detalles en los dispositivos de E/S identificando algunos tipos. Se accede a cada tipo general a través de un conjunto estandarizado de funciones: una interfaz. Las diferencias están encapsuladas en módulos del kernel llamados manejadores (drivers) de dispositivos que internamente se adaptan a dispositivos específicos, pero que exportar una de las interfaces estándar.
Figura 12.7 Estructura de E/S del kernel.
La figura 12.7 ilustra cómo las E/S relacionadas con partes del kernel están estructuradas en capas de software.
El propósito de la capa de manejador (driver) de dispositivo es ocultar las diferencias entre manejadores (drivers) de dispositivos del subsistema de E/S del kernel, tanto como el sistema de E/S, las llamadas encapsulan el comportamiento de los dispositivos en unas pocas clases genéricas que ocultan diferencias de hardware de las aplicaciones. Hacer que el subsistema de E/S sea independiente del hardware simplifica el trabajo del desarrollador del sistema operativo. Eso también beneficia a los fabricantes de hardware. O bien diseñan nuevos dispositivos para ser compatible con una interfaz de controlador de host existente (como SATA), o se escribe manejadores (drivers) de dispositivo para conectar el nuevo hardware a los sistemas operativos populares. Así, podemos conectar nuevos periféricos a una computadora sin esperar el proveedor del sistema operativo para desarrollar el código de soporte.
Desafortunadamente para los fabricantes de dispositivos y hardware, cada tipo de sistema operativo tiene sus propios estándares para la interfaz dispositivo- (drivers). Un dispositivo dado puede enviarse con varios (drivers) de dispositivo, por ejemplo, controladores para Windows, Linux, AIX y macOS. Los dispositivos varían en muchas dimensiones, como se ilustra en Figura 12.8.
• Secuencia (stream) o bloque de caracteres. Un dispositivo de flujo de caracteres transfiere los bytes uno por uno, mientras que un dispositivo de bloque transfiere un bloque de bytes como una unidad.
• Método de acceso: Acceso secuencial o aleatorio. Un dispositivo secuencial transfiere datos en un orden determinado por el dispositivo, mientras que el usuario de un dispositivo de acceso aleatorio puede indicarle al dispositivo que busque cualquier ubicación de los datos disponibles de almacenamiento.
Figura 12.8 Características de los dispositivos de E/S
• Planificación de la transferencia: Sincrónico o asincrónico. Un dispositivo sincrónico realiza transferencias de datos con tiempos de respuesta predecibles, en coordinación con otros aspectos del sistema. Un dispositivo asincrónico exhibe Tiempos de respuesta irregular o impredecibles y no coordinados con otra computadora.
• Compartición: Compartible o dedicado. Un dispositivo que se puede compartir puede ser utilizado simultáneamente por varios procesos o hilos; un dispositivo dedicado no.
• Velocidad de operación. Las velocidades del dispositivo van desde unos pocos bytes por segundo hasta gigabytes por segundo.
• Sentido de la E/S: lectura/escritura, sólo lectura, sólo una escritura una vez. Algunos dispositivos realizan tanto entrada como salida, pero otros sólo admiten una dirección de transferencia de datos. Algunos permiten que los datos se modifiquen después de la escritura, pero otros sólo se pueden escribir una vez y son de sólo lectura a partir de entonces.
A los efectos del acceso a la aplicación, muchas de estas diferencias están ocultas por el sistema operativo, y los dispositivos se agrupan en unos pocos tipos convencionales. Se ha descubierto que los estilos de acceso a dispositivos son útiles y aunque las llamadas exactas al sistema pueden diferir entre los sistemas, las categorías de dispositivos son bastante estándar. Las funciones de acceso incluyen E/S de bloque, E/S de flujo de caracteres, acceso a archivos asignados en memoria y socket de red. Los sistemas operativos también proporcionan llamadas especiales al sistema para acceder algunos dispositivos adicionales, como un reloj con la hora del día y un temporizador. Los sistemas operativos proporcionan un conjunto de llamadas al sistema para visualización gráfica, video y dispositivos de audio.
La mayoría de los sistemas operativos también tienen un escape (o puerta trasera) que de manera transparente pasa comandos arbitrarios de una aplicación a un driver de dispositivo. En UNIX, esta llamada al sistema es ioctl () (para "control de E/S"). La llamada al sistema ioctl () permite que una aplicación acceda a cualquier funcionalidad que pueda ser implementada por cualquier driver de dispositivo, sin la necesidad de inventar una nueva llamada al sistema. La llamada al sistema ioctl() tiene tres argumentos. El primero es un identificador de dispositivo que conecta la aplicación al driver haciendo referencia a un dispositivo de hardware administrado por ese driver. El segundo es un entero que selecciona uno de los comandos implementados en el driver. El tercero es un puntero a una estructura de datos arbitraria en la memoria que permite a la aplicación y al driver comunicar cualquier control necesario información o datos.
El identificador de dispositivo en UNIX y Linux es una tupla de números de "mayor y menor" de dispositivo. El número principal es el tipo de dispositivo y el segundo es la instancia de ese dispositivo. Por ejemplo, considere estos dispositivos SSD en un sistema. Si uno emite un comando:
% ls -l / dev / sda *
entonces la siguiente salida
brw-rw ---- 1 disco raíz 8, 0 16 de marzo 09:18 / dev / sda
brw-rw ---- 1 disco raíz 8, 1 de marzo de 16 09:18 / dev / sda1
brw-rw ---- 1 disco raíz 8, 2 de marzo de 16 09:18 / dev / sda2
brw-rw ---- 1 disco raíz 8, 3 de marzo 16 09:18 / dev / sda3
muestra que 8 es el número de dispositivo principal. El sistema operativo usa esa información para enrutar las solicitudes de E/S al driver de dispositivo apropiado. Los números menores 0, 1, 2 y 3 indican la instancia del dispositivo, lo que permite solicitudes de E/S a una entrada de dispositivo para seleccionar el dispositivo exacto para la solicitud.
12.3.1 Dispositivos de bloque y caracteres
La interfaz: dispositivo orientado a bloque, captura todos los aspectos necesarios para acceder a las unidades de disco y otros dispositivos orientados a bloques. Se espera que el dispositivo comprenda comandos como read () y write (). Si es un dispositivo de acceso aleatorio, se espera además que tengaun comando seek () para especificar qué bloque siguiente se transferirá. Las aplicaciones normalmente acceden a dicho dispositivo a través de una interfaz de sistema de archivos. Podemos ver que read (), write () y seek () capturan el comportamiento esencial de los dispositivos de almacenamiento en bloque, de modo que las aplicaciones estén aisladas de las diferencias de bajo nivel entre esos dispositivos.
El sistema operativo en sí, así como las aplicaciones especiales como sistemas de administración de bases de datos, pueden preferir acceder a un dispositivo de bloque como una matriz lineal simple de bloques. Este modo de acceso a veces se denomina E/S sin procesar (cruda). Si la aplicación realiza su propio almacenamiento en búfer, entonces no necesita el buffer de sistema de archivos. Asimismo, si una aplicación proporciona su propio bloqueo de regiones, luego cualquier servicio de bloqueo del sistema operativo sería redundante al menos y contradictorio en el peor de los casos. Para evitar estos conflictos, el acceso al dispositivo sin procesar pasa el control del dispositivo directamente a la aplicación, dejando que el sistema operativo se haga a un costado. Lamentablemente no hay servicios del sistema operativo que sean realizados por este dispositivo. Una situación intermedia es que el sistema operativo permita un modo de operación sobre un archivo que deshabilita el almacenamiento en búfer y el bloqueo. En el mundo UNIX, esto se llama E/S directa.
El acceso a archivos asignados en memoria se puede superponer a los controladores de dispositivos de bloque. En lugar de ofrecer operaciones de lectura y escritura, una interfaz mapeada en memoria proporciona acceso al almacenamiento en disco a través de una matriz de bytes en la memoria principal. La llamada al sistema que asigna un archivo a la memoria devuelve la dirección de la memoria virtual que contiene una copia del archivo. Las transferencias de datos reales se realizan solo cuando sea necesario satisfacer el acceso a la imagen de la memoria. Porque las transferencias son manejadas por el mismo mecanismo que el que se usa para las aplicaciones virtuales por paginación bajo demanda. el acceso a la memoria, la E/S mapeada en memoria es eficiente. El mapeo de memoria también es conveniente para los planificadores: el acceso a un archivo asignado en memoria es tan simple como leer y escribir en la memoria. Los Sistemas operativos que ofrecen memoria virtual suele utilizar la interfaz de mapeo para los servicios del kernel. Por ejemplo, para ejecutar un programa, el sistema operativo asigna el ejecutable a la memoria y luego transfiere el control a la dirección de entrada del ejecutable. La interfaz de mapeo también se usa comúnmente para acceder al kernel para intercambiar espacio en el disco (el swap).
Un teclado es un ejemplo de un dispositivo al que se accede a través de una interfaz de secuencia de caracteres. Las llamadas al sistema básicas en esta interfaz habilitan una aplicación para (obtener) get() o (poner) put() un carácter. Además de esta interfaz, las bibliotecas se pueden construir para ofrecer acceso de una línea a la vez, con almacenamiento en búfer y servicios de edición (por ejemplo, cuando un usuario escribe un retroceso, el carácter anterior se elimina del flujo de entrada). Este estilo de acceso es conveniente para dispositivos de entrada como teclados, ratones y módems que producen datos para ingresarlos "espontáneamente" —Es decir, en ocasiones, la aplicación no necesariamente puede predecirlo. Este estilo de acceso también es bueno para dispositivos de salida como impresoras y placas de audio, que se ajustan naturalmente al concepto de flujo lineal de bytes.
12.3.2 Dispositivos de red
Debido a que el rendimiento y las características de direccionamiento de la E/S de red difieren significativamente de los de E/S de disco, la mayoría de los sistemas operativos proporcionan una red Interfaz de E/S que es diferente de la interfaz de lectura () - escritura () - búsqueda () utilizado para discos. Una interfaz disponible en muchos sistemas operativos, incluidos UNIX y Windows, es la interfaz de conexión de red.
Piense en un enchufe (socket) de pared para electricidad: cualquier aparato eléctrico puede conectado. Por analogía, las llamadas del sistema en la interfaz del enchufe permiten a la aplicación crear un enchufe, para conectar un enchufe local a una dirección remota (que conecta esta aplicación en un enchufe creado por otra aplicación), para escuchar cualquier aplicación remota para conectarla al enchufe local y enviar y recibir paquetes a través de la conexión. Para apoyar la implementación de servidores de red, la interfaz de socket también proporciona una función llamada select () que gestiona un conjunto de sockets. Una llamada select () devuelve información sobre qué sockets tienen un paquete en espera de ser recibido y qué sockets tienen espacio para aceptar un paquete para ser enviado. El uso de select () elimina el sondeo y espera ocupada que de otro modo sería necesario para la E/S de la red. Estas funciones encapsulan los comportamientos esenciales de las redes, lo que facilita enormemente la creación de aplicaciones distribuidas que pueden utilizar cualquier pila de hardware y protocolo de red subyacente.
Muchos otros enfoques para la comunicación entre procesos y la comunicación en red se han aplicado. Por ejemplo, Windows proporciona una interfaz a la tarjeta de interfaz de red y una segunda interfaz a la red Protocolos. En UNIX, que tiene una larga historia de pruebas para tecnología de redes, encontramos tuberías semidúplex, FIFOs full-duplex, STREAMS full-duplex, colas de mensajes y sockets. La información sobre las redes UNIX se proporciona en Sección C.9.
12.3.3 Relojes y temporizadores
La mayoría de las computadoras tienen relojes de hardware y temporizadores que proporcionan tres funciones:
• Dar la hora actual.
• Indicar el tiempo transcurrido.
• Configurar un temporizador para activar la operación X en el momento T (despertador)
Estas funciones son muy utilizadas por el sistema operativo, así como aplicaciones sensibles al tiempo. Desafortunadamente, las llamadas al sistema que implementan estas funciones no están estandarizadas en todos los sistemas operativos.
El hardware para medir el tiempo transcurrido y desencadenar operaciones se llama un temporizador de intervalo programable. Se puede configurar para esperar una cierta cantidad de tiempo y luego generar una interrupción, y se puede configurar para hacer esto una vez o para repetir el proceso para generar interrupciones periódicas. El planificador utiliza este mecanismo para generar una interrupción que expulsará un proceso al final de su quantum de tiempo. El subsistema de E/S de disco lo usa para invocar el vaciado periódico de los búferes en el disco y el subsistema de red lo usa para cancelar operaciones que avanzan demasiado lento debido a la congestión o fallas de la red. El sistema operativo también puede proporcionar una interfaz para que los procesos de usuario utilicen temporizadores. El sistema operativo puede admitir más solicitudes de temporizador que el número de canales de hardware del temporizador mediante la simulación de relojes virtuales. Para hacerlo, el kernel (o el driver del dispositivo temporizador) mantiene una lista de interrupciones deseadas por su propia cuenta rutinas y por solicitudes de usuario, ordenadas en orden de primera vez. Configura el temporizador Cuando el temporizador se interrumpe, el kernel le indica al solicitante y recarga el temporizador con la próxima hora más temprana.
Las computadoras tienen hardware de reloj que se utiliza para una variedad de propósitos. Las PC modernas incluyen un temporizador de eventos de alto rendimiento (HPET), que se ejecuta en tasas en el rango de 10 MHZ. Tiene varios comparadores que se pueden configurar para disparar una vez o repetidamente cuando el valor que tienen coincide con el del HPET. El disparador genera una interrupción y el reloj del sistema operativoLas rutinas de administración determinan para qué fue el temporizador y qué acción tomar. La precisión de los disparadores está limitada por la resolución del temporizador, juntos con la sobrecarga de mantener relojes virtuales. Además, el temporizador se utiliza para mantener el reloj del sistema con la hora del día, el reloj del sistema puede variar. La desviación se puede corregir mediante protocolos diseñados para ese propósito, como NTP, el protocolo de tiempo de red, que utiliza sofisticados cálculos de latencia para mantener el reloj de una computadora con una precisión casi equivalente a los niveles de un reloj atómico. En la mayoría de las computadoras, el reloj de hardware se construye a partir de un contador de alta frecuencia. En algunas computadoras, el valor de este contador se puede leer desde un registro de dispositivo, en cuyo caso el contador puede considerarse un reloj de alta resolución. Aunque este reloj no genere interrupciones, ofrece medidas precisas de intervalos de tiempo.
12.3.4 E/S asíncronas y sin bloqueo
Otro aspecto de la interfaz de llamada al sistema se relaciona con la elección entre E/S con bloqueo y E/S sin bloqueo. Cuando una aplicación emite una llamada al sistema de bloqueo, la ejecución del hilo de llamada se suspende. El hilo se mueve de la cola de ejecución del sistema operativo a una cola de espera. Una vez finalizada la llamada al sistema, el hilo se mueve de nuevo a la cola de ejecución, donde es elegible para reanudar la ejecución. Cuando reanude la ejecución, recibirá los valores devueltos por la llamada al sistema. Las acciones físicas realizadas por los dispositivos de E/S son generalmente asincrónicos: requieren una cantidad de tiempo variable o impredecible. Sin embargo, los sistemas operativos proporcionan llamadas al sistema bloqueantes para la aplicación interfaz, porque al bloquear la aplicación es más fácil de escribir que si no se bloqueara la aplicación.
Algunos procesos a nivel de usuario necesitan E/S sin bloqueo. Un ejemplo es una interfaz de usuario que recibe entrada de teclado y mouse mientras procesa y muestra datos en la pantalla. Otro ejemplo es una aplicación de video que lee marcos de un archivo en el disco mientras se descomprime y muestra simultáneamente la salida en la pantalla.
Una forma en que un escritor de aplicaciones puede superponer la ejecución con la E/S es escribir una aplicación multiproceso. Algunos hilos pueden realizar llamadas al sistema de bloqueo, mientras que otros continúan ejecutándose. Algunos sistemas operativos proporcionan Llamadas al sistema no bloqueantes de E/S. Una llamada sin bloqueo no detiene la ejecución del hilo por un tiempo prolongado. En cambio, regresa rápidamente, con un valor de retorno que indica cuántos bytes se transfirieron.
Una alternativa a una llamada al sistema sin bloqueo es una llamada al sistema asíncrona. Una llamada asincrónica regresa inmediatamente, sin esperar a que la E/S completar. El hilo continúa ejecutando su código. La finalización de la E/S en algún momento futuro se comunica al hilo, ya sea a través de la configuración de alguna variable en el espacio de direcciones del hilo o mediante la activación de una señal o interrupción de software o una rutina de devolución de llamada que se ejecuta fuera el flujo de control lineal del hilo. La diferencia entre Las llamadas al sistema no bloqueantes y asincrónicas es que un read () sin bloqueo regresa inmediatamente con los datos disponibles: el número total de bytes solicitados, menos, o ninguno en absoluto. Una llamada asincrónica read (), por ejemplo, solicita una transferencia que será realizada en su totalidad, pero se completará en algún momento futuro. Estos dos métodos de E/S se muestran en la Figura 12.9.
Las actividades asincrónicas ocurren en todos los sistemas operativos modernos. Frecuentemente, no están expuestos a usuarios o aplicaciones, sino que están contenidos dentro de la operación del sistema operativo. Las E/S de dispositivo de almacenamiento secundario y de red son ejemplos útiles. De forma predeterminada, cuando una aplicación emite una solicitud de red o una solicitud de escritura del dispositivo de almacenamiento, el sistema operativo se da cuenta de la solicitud, la almacena en búfer a la solicitud de E/S y vuelve a la aplicación. Cuando sea posible, para optimizar el rendimiento general del sistema, el sistema operativo completa la solicitud. Si ocurre una falla del sistema mientras tanto, la aplicación perderá cualquier Solicitud "al vuelo". Por lo tanto, los sistemas operativos suelen limitar la duración de tiempo que almacenarán una solicitud en búfer.
Figura 12.9 Dos métodos de E/S: (a) síncrono y (b) asíncrono
Algunas versiones de UNIX descargan sus búferes de almacenamiento cada 30 segundos, por ejemplo, o cada solicitud se vacía dentro de los 30 segundos de su ocurrencia. Los sistemas proporcionan una forma de permitir que las aplicaciones soliciten una descarga de algunos búferes (como búferes de almacenamiento secundarios) para que los datos puedan ser forzados al almacenamiento secundario sin esperar el intervalo de descarga del búfer. La coherencia de los datos dentro de las aplicaciones la mantiene el kernel, que lee datos de sus búferes antes de enviar solicitudes de E/S a los dispositivos, asegurando que los datos aún no escritos se devuelven a un lector que lo solicite. Es posible que los hilos que realizan E/S en el mismo archivo no reciban datos consistentes, dependiendo de cómo el kernel implemente su E/S. En esta situación, los hilos puede que necesiten utilizar protocolos de bloqueo. Algunas solicitudes de E/S deben realizarse inmediatamente, por lo que las llamadas al sistema de E/S suelen tener una forma de indicar que una determinada solicitud, o E/S a un dispositivo específico, debe realizarse sincrónicamente.
Un buen ejemplo de comportamiento sin bloqueo es la llamada al sistema select () para enchufes (sockets) de red. Esta llamada al sistema toma un argumento que especifica un máximo tiempo de espera. Al establecerlo en 0, un hilo puede sondear la actividad de la red sin bloquear. Pero el uso de select () introduce una sobrecarga adicional, porque la llamada select () solo comprueba si la E/S es posible. Para una transferencia de datos, select () debe ir seguido de algún tipo de comando de lectura () o escritura (). Una variación de este enfoque, que se encuentra en Mach, es una llamada bloqueante de lectura múltiple. Especifica lecturas deseadas para varios dispositivos en una llamada al sistema y regresa tan pronto como alguno de ellos se complete.
12.3.5 E/S vectorizada
Algunos sistemas operativos proporcionan otra variación importante de la E/S a través de su interface de aplicación. La E/S vectorizada permite que una llamada al sistema realice múltiples operaciones de E/S que involucran múltiples ubicaciones. Por ejemplo, la llamada al sistema readv de UNIX acepta un vector de múltiples búferes y lee de una fuente a ese vector o escribe desde ese vector a un destino. La misma transferencia podría hacerse con varias invocaciones individuales de llamadas al sistema, pero este método de dispersión-recopilación es útil por varias razones.
Múltiples búferes separados pueden transferir su contenido a través de una llamada al sistema, evitando el cambio de contexto y la sobrecarga de llamadas al sistema. Sin E/S vectorizada, es posible que primero sea necesario transferir los datos a un búfer más grande en el orden correcto y luego se transmite, lo cual es ineficiente. Además, algunas de las versiones de dispersión-recopilación proporcionan atomicidad, asegurando que todas las E/S estén hechas sin interrupción (y evitando la corrupción de datos si otros hilos también están realizando E/S que involucran esos búferes). Cuando es posible, los planificadores hacen uso de funciones de E/S de dispersión y recopilación para aumentar el rendimiento y disminuir el sistema de gastos generales.
12.4 Subsistema de E/S del kernel
Los kernels brindan muchos servicios relacionados conla E/S. Varios servicios: planificación, almacenamiento en búfer, almacenamiento en caché, spooling, reserva de dispositivos y manejo de errores son provistos por el subsistema de E/S del kernel y se basa en el hardware y la infraestructura de drivers de dispositivos. El subsistema de E/S también es responsable de protegerse a sí mismo de procesos errantes y usuarios malintencionados.
12.4.1 Planificación de E/S
Planificar un conjunto de solicitudes de E/S significa determinar un buen orden en el cual ejecutarlos. El orden en el que las aplicaciones emiten llamadas al sistema rara vez es la mejor elección. La planificación puede mejorar el rendimiento general del sistema, puede compartir acceso al dispositivo de manera justa entre procesos y puede reducir el tiempo de espera promedio para que se complete la E/S. Aquí hay un ejemplo simple para ilustrar. Supongamos que un disco brazo está cerca del comienzo de un disco y que tres aplicaciones emiten llamadas al sistema de lectura de un bloque a ese disco. La aplicación 1 solicita un bloque cerca del final del disco, la aplicación 2 solicita una cerca del principio y la aplicación 3 solicita una en el medio del disco. El sistema operativo puede reducir la distancia que el brazo del disco se desplace atendiendo las aplicaciones en el orden 2, 3, 1. La Reorganización del orden de servicio de esta manera es la esencia de la planificación de E/S.
Los desarrolladores de sistemas operativos implementan la planificación manteniendo una cola espera de solicitudes para cada dispositivo. Cuando una aplicación emite una Llamada al sistema de E/S por bloque, la solicitud se coloca en la cola de ese dispositivo. El planificador reorganiza la cola de E/S en el orden que mejore la eficiencia general del sistema y el tiempo medio de respuesta experimentado por las aplicaciones. El sistema operativo también puede tratar de ser justo, de modo que ninguna aplicación reciba especialmente mal servicio, o puede dar un servicio prioritario para solicitudes sensibles a retrasos. Por ejemplo, las solicitudes del subsistema de memoria virtual pueden tener prioridad sobre solicitudes de solicitud. Se detallaron varios algoritmos de planificación para E/S de disco en la Sección 11.2.
Cuando un kernel admite E/S asincrónicas, debe poder realizar un seguimiento de muchas solicitudes de E/S al mismo tiempo. Para ello, el sistema operativo podría adjuntar la cola de espera a una tabla de estado de dispositivo. El kernel gestiona esta tabla, que contiene una entrada para cada dispositivo de E/S, como se muestra en la Figura 12.10. Cada entrada de la tabla indica el tipo, la dirección y el estado del dispositivo (no funciona, inactivo u ocupado). Si el dispositivo está ocupado con una solicitud, el tipo de solicitud y los otros parámetros se almacenarán en la entrada de la tabla para ese dispositivo.
Figura 12.10 Tabla de estado del dispositivo.
La planificación de operaciones de E/S es una forma en la que el subsistema de E/S mejora la eficiencia de la computadora. Otra forma es utilizar el espacio de almacenamiento en la memoria o en cualquier otro lugar de la jerarquía de almacenamiento mediante almacenamiento en búfer, almacenamiento en caché o spooling (un buffer especial en disco).
12.4.2 Almacenamiento en búfer
Un buffer, por supuesto, es un área de memoria que almacena los datos que se transfieren entre dos dispositivos o entre un dispositivo y una aplicación. El almacenamiento en búfer se realiza por tres razones. Una razón es hacer frente a un desajuste de velocidad entre el productor y consumidor de un flujo de datos. Suponga, por ejemplo, que un archivo está siendo recibido a través de Internet para su almacenamiento en un SSD. La velocidad de la red puede ser mil veces más lento que el disco. Entonces se crea un búfer en la memoria principal para acumular los bytes recibidos de la red. Cuando se haya llenado el búfer. Dado que la escritura no es instantánea y la interfaz de red aún necesita un lugar para almacenar datos entrantes adicionales, se utilizan dos búferes. Después que la red llena el primer búfer, se solicita la escritura de la unidad. Entonces la red comienza a llenar el segundo búfer mientras que el primer búfer se escribe en el almacenamiento. Para cuando la red ha llenado el segundo búfer, la escritura de la unidad desde el primero ya se deben haber completado, por lo que la red puede volver al primer búfer mientras el drive escribe el segundo. Este doble búfer desacopla al productor de datos del consumidor, relajando así los requisitos de tiempo entre ellos. La necesidad de este desacoplamiento se ilustra en la Figura 12.11, que enumera la enorme diferencia en las velocidades del dispositivo para interfaces y hardware de computación típico.
Un segundo uso del almacenamiento en búfer es proporcionar adaptaciones para dispositivos que tienen diferentes tamaños de transferencia de datos. Tales disparidades son especialmente comunes en redes computacionales, donde los búferes se utilizan ampliamente para la fragmentación y reensamblaje de mensajes. En el lado del envío, un mensaje grande está fragmentado en pequeños paquetes de red. Los paquetes se envían a través de la red y del lado receptor los coloca en un búfer de reensamblaje para formar una imagen de los datos-fuente. 
Figura 12.11 Velocidades de interfaz y dispositivos de E/S de centros de datos y PC comunes
Un tercer uso del almacenamiento en búfer es admitir la semántica de copia para la E/S de la aplicación. Un ejemplo aclarará el significado de "semántica de copia". Suponga que una aplicación tiene un búfer de datos que desea escribir en el disco. Una llamada al sistema write (), que proporciona un puntero al búfer y un entero que especifica el número de bytes a escribir. Después de que regresa la llamada al sistema, ¿qué sucede? si la aplicación cambia el contenido del búfer? Con semántica de copia, se garantiza que la versión de los datos escritos en el disco sea la versión actual de la llamada al sistema de la aplicación, independientemente de cualquier cambio posterior en el búfer de la aplicación. Una forma sencilla en la que el sistema operativo puede garantizar de que la semántica de copia es para que la llamada al sistema write () copie los datos a la aplicación en un búfer del kernel antes de devolver el control a la aplicación. La escritura en disco se realiza desde el búfer del kernel, de modo que, el cambio posterior al búfer de aplicación no tiene ningún efecto. Copia de datos entre búferes del kernel y el espacio de datos de la aplicación es común en los sistemas operativos, a pesar de la sobrecarga que introduce esta operación, debido a la semántica limpia. El mismo efecto se puede obtener de manera más eficiente mediante el uso inteligente de la asignación de memoria virtual y protección de página de copia en escritura.
12.4.3 Almacenamiento en caché
Una caché es una región de memoria rápida que contiene copias de datos. El Acceso a la copia en caché es más eficiente que el acceso al original. Por ejemplo, las instrucciones del proceso que se está ejecutando actualmente están almacenadas en disco, (cacheadas) en memoria principal y copiadas nuevamente en las cachés de nivel 1 y 2 de la CPU. La diferencia entre un búfer y una caché es que un búfer puede contener una única copia de elementos de datos, mientras que una caché, por definición, contiene una copia en almacenamiento más rápido de un artículo que reside en otro lugar.
El almacenamiento en caché y el almacenamiento en búfer son funciones distintas, pero a veces una región de la memoria se puede utilizar para ambos propósitos. Por ejemplo, para preservar la semántica de la copia y para permitir una planificación eficiente de E/S de disco, el sistema operativo utiliza búferes en la memoria principal para almacenar datos del disco. Estos búferes también se utilizan como caché, para mejorar la eficiencia de E/S para archivos que son compartidos por aplicaciones o que se están escribiendo y releyendo rápidamente. Cuando elkernel recibe una E/S de archivo solicitud, el kernel primero accede al búfer caché para ver si esa región del archivo ya está disponible en la memoria principal. Si es así, una E/S de disco físico puede evitarse o aplazarse. Además, las escrituras de disco se acumulan en el búfer caché durante varios segundos, de modo que se recopilen grandes transferencias para permitir planificar la escritura. Esta estrategia de retrasar las escrituras para mejorar la eficiencia de E/S es discutido, en el contexto del acceso remoto a archivos, en la Sección 19.8.
12.4.4 Spooling y reserva de dispositivos
Un spool es un búfer que contiene la salida de un dispositivo, como una impresora, que no puede aceptar flujos de datos intercalados. Aunque una impresora solo puede realizar un trabajo a la vez varias aplicaciones pueden desear imprimir su salida al mismo tiempo, sin mezclar su producción. El sistema operativo resuelve este problema interceptando toda la salida a la impresora. La salida de cada aplicación se pone en cola a un archivo de almacenamiento secundario independiente. Cuando una aplicación termina de imprimir, el sistema de cola pone el archivo en la cola de impresión correspondiente y lo envía a la impresora. El sistema de cola copia los archivos de cola en cola en la impresora de uno en uno. En algunos sistemas operativos, la puesta en cola es administrada por un proceso demonio del sistema. En otros, es manejado por un hilo en el kernel. En cualquier caso, el sistema operativo proporciona una interfaz de control que permite a los usuarios y administradores del sistema mostrar, eliminar los trabajos no deseados antes de que se impriman, suspender imprimir mientras se repara la impresora, etc.
Algunos dispositivos, como unidades de cinta e impresoras, no pueden multiplexar de manera útil las solicitudes de E/S de múltiples aplicaciones concurrentes. El Spooling es una forma en la que los sistemas operativos pueden coordinar la salida concurrente. Otra forma de tratar El acceso simultáneo al dispositivo es para proporcionar facilidades explícitas para la coordinación. Algunos sistemas operativos (incluido VMS) brindan soporte para el acceso exclusivo al dispositivo habilitando un proceso para asignar un dispositivo inactivo y desasignar ese dispositivo cuando ya no se necesita. Otros sistemas operativos imponen un límite de que sólo uno abra el identificador de archivo a dicho dispositivo. Muchos sistemas operativos proporcionan funciones que permiten a los procesos coordinar el acceso exclusivo entre ellos. Por ejemplo, Windows proporciona llamadas al sistema para esperar hasta que un objeto de dispositivo se convierta en disponible. También tiene un parámetro para la llamada al sistema OpenFile () que declara los tipos de acceso que se permitirán a otros hilos concurrentes. En estos sistemas, depende de las aplicaciones evitar un deadlock.
12.4.5 Manejo de errores
Un sistema operativo que utiliza memoria protegida puede proteger contra muchos tipos de errores de hardware y aplicaciones, de modo que una falla completa del sistema no es el resultado habitual de un mal funcionamiento mecánico menor. Los Dispositivos y Las transferencias de E/S pueden fallar de muchas formas, ya sea por razones transitorias, como cuando una red se sobrecarga, o por razones "permanentes", como cuando un driver de disco se vuelve defectuoso. Los sistemas operativos a menudo pueden compensar eficazmente Fallos transitorios. Por ejemplo, una falla de lectura () de disco da como resultado un reintento de lectura (), y un error send () en la red da como resultado un resend (), si el protocolo así lo especifica. Desafortunadamente, si un componente importante experimenta una falla permanente, es poco probable que el sistema operativo se recupere.
Como regla general, una llamada al sistema de E/S devolverá un bit de información sobre el estado de la llamada, lo que significa éxito o fracaso. En un sistema operativo UNIX, se utiliza una variable entera adicional denominada errno para devolver un código de error (uno de unos cien valores) que indica la naturaleza general del fallo (por ejemplo, un argumento fuera de rango, puntero incorrecto o archivo no abierto). Por el contrario, algunos hardware pueden proporcionar información de error muy detallada, aunque muchos sistemas operativos actuales no están diseñados para transmitir esta información a la aplicación. Por ejemplo, una falla de un dispositivo SCSI es informado por el protocolo SCSI en tres niveles de detalle: una clave de sentido que identifica la naturaleza general de la falla, como un error de hardware o de una solicitud; un código de sentido adicional que establece la categoría de falla, como un parámetro de comando incorrecto o falla en la autocomprobación; y un código de detección adicional, cualificación que ofrece aún más detalles, como, qué parámetro de comando da error o qué subsistema de hardware falló en su autoprueba. Además, muchos SCSI Los dispositivos mantienen páginas internas de información de registro de errores que se pueden solicitar por el anfitrión, pero rara vez lo son.
12.4.6 Protección de E/S
Los errores están estrechamente relacionados con el tema de la protección. Un proceso de usuario puede, accidentalmente o deliberadamente intentar interrumpir el funcionamiento normal de un sistema cuando intenta emitir instrucciones de E/S ilegales. Podemos utilizar varios mecanismos para asegurarnos de que tales interrupciones no puedan tener lugar en el sistema.
Para evitar que los usuarios realicen E/S ilegales, definimos todas las instrucciones de E/S ser instrucciones privilegiadas. Por lo tanto, los usuarios no pueden emitir instrucciones de E/S directamente; deben hacerlo a través del sistema operativo. Para hacer una E/S, un programa de usuario ejecuta una llamada al sistema para solicitar que el sistema operativo realice E/S en su nombre (Figura 12.12). El sistema operativo, que se ejecuta en modo monitor, comprueba que la solicitud es válida y, si lo es, la E/S solicitada. El sistema operativo luego regresa al usuario.
Además, cualquier ubicación en memoria de un puerto de E/S y mapeada en memoria debe estar protegida del acceso de los usuarios por el sistema de protección de memoria. Tenga en cuenta que un kernel no puede simplemente negar el acceso de todos los usuarios. La mayoría del software de videojuegos y gráficos de edición y reproducción necesita acceso directo a gráficos mapeados en memoria y al controlador de memoria para acelerar el rendimiento de los gráficos, por ejemplo. Los kernel podría en este caso proporcionar un mecanismo de bloqueo para permitir una sección de memoria de gráficos (que representa una ventana en la pantalla) que se asigne a un proceso a la vez.
12.4.7 Estructuras de datos del kernel
El kernel necesita mantener información de estado sobre el uso de componentes de E/S. Eso lo hace a través de una variedad de estructuras de datos en el kernel, como la tabla de archivos abiertos, estructura discutida en la Sección 14.1. El kernel utiliza muchas estructuras similares para realizar un seguimiento de las conexiones de red, las comunicaciones entre caracteres y dispositivos y otras actividades de E/S.
Figura 12.12 Uso de una llamada al sistema para realizar E/S.
UNIX proporciona acceso al sistema de archivos a una variedad de entidades, como archivos de usuario, dispositivos en bruto y los espacios de direcciones de los procesos. Aunque cada una de estas entidades admite una operación read (), la semántica difiere. Por ejemplo, para leer un archivo de usuario, el kernel necesita sondear la caché del búfer antes de decidir si realizar una E/S de disco. Para leer un disco sin formato, el kernel debe asegurarse que el tamaño de la solicitud es un múltiplo del tamaño del sector del disco y está alineado en un límite del sector. Para leer una imagen de proceso, solo es necesario copiar los datos de memoria. UNIX encapsula estas diferencias dentro de una estructura uniforme utilizando una técnica orientada a objetos. Elregistro de archivo abierto, que se muestra en la Figura 12.13, contiene una tabla de despacho que contiene punteros a las rutinas apropiadas, dependiendo del tipo de archivo.
Algunos sistemas operativos utilizan métodos orientados a objetos aún más ampliamente. Por ejemplo, Windows usa una implementación de paso de mensajes para E/S. Una solicitud de E/S se convierte en un mensaje que se envía a través del kernel a el administrador de E/S y luego al driver de dispositivo, cada uno de los cuales puede cambiar el contenido del mensaje. Para la salida, el mensaje contiene los datos que se escribirán. Para la entrada, el mensaje contiene un búfer para recibir los datos. El enfoque de paso de mensaje puede agregar sobrecarga (overhead), en comparación con las técnicas de procedimiento que utilizan estructuras de datos compartidas, pero simplifica la estructura y el diseño de las E/S sistema y agrega flexibilidad.
Figura 12.13 Estructura del kernel de E/S de UNIX.
12.4.8 Gestión de energía
Las computadoras que residen en centros de datos pueden parecer muy alejadas de los problemas de uso de energía, pero a medida que aumentan los costos de energía y el mundo se vuelve cada vez más preocupado por los efectos a largo plazo de las emisiones de gases de efecto invernadero, los centros de datos se han convertido en motivo de preocupación y en un objetivo para aumentar la eficiencia. El uso de electricidad genera calor y los componentes de la computadora pueden fallar debido a altas temperaturas, por lo que el enfriamiento también es parte de la ecuación. Considere ese enfriamiento en Un centro de datos moderno puede utilizar el doble de electricidad que la energía que el equipo necesita. Muchos enfoques para la optimización de la energía del centro de datos están en uso, que van desde intercambiar aire del centro de datos sin aire lateral, enfriar con fuentes naturales como agua de lago y paneles solares.
Los sistemas operativos juegan un papel en el uso de energía (y por lo tanto en la generación de calor y enfriamiento). En entornos de computación en la nube, las cargas de procesamiento pueden ajustarse mediante herramientas de supervisión y gestión para evacuar todos los procesos del usuario de los sistemas, inactivar esos sistemas y apagarlos hasta que requiera su uso. Un sistema operativo podría analizar su carga y, si la carga es baja y el hardware lo permite, como CPU y dispositivos de E/S externos.
Los cores de CPU se pueden suspender cuando la carga del sistema no los requiere y se reanuda cuando la carga aumenta y se necesiten más cores para ejecutar la cola de hilos. Su estado, por supuesto, debe guardarse cuando esté en suspensión y restaurados cuando se relancen. Esta función es necesaria en los servidores, porque los servidores de un centro de datos pueden utilizar grandes cantidades de electricidad y deshabilitar cores innecesarios puede disminuir las necesidades de electricidad (y refrigeración).
En la computación móvil, la gestión de la energía se convierte en un aspecto de alta prioridad del sistema operativo. Minimizar el uso de energía y, por lo tanto, maximizar la batería la vida aumenta la usabilidad de un dispositivo y lo ayuda a competir con dispositivos alternativos. Los dispositivos móviles de hoy ofrecen la funcionalidad de los de gama alta de ayer escritorio, pero funcionan con baterías y son lo suficientemente pequeñas como para caber en su bolsillo. Para proporcionar una duración satisfactoria de la batería, los sistemas operativos de los móviles modernos están diseñados desde cero para cuidar la energía. Examinemos en detalle tres características principales que permiten a los populares Sistema móvil Android para maximizar la duración de la batería: colapso de energía, nivel de componente administración de energía y despertadores. 
El colapso de energía es la capacidad de poner un dispositivo en un estado de sueño muy profundo. El dispositivo usa solo un poco más de energía que si estuviera completamente apagado, sin embargo, todavía es capaz de responder a estímulos externos, como que el usuario presione un botón, momento en el que se enciende rápidamente. Se logra el colapso del poder apagando muchos de los componentes individuales dentro de un dispositivo, como la pantalla, los altavoces y el subsistema de E/S, para que no consuman energía. El sistema operativo coloca a la CPU en su estado de suspensión más bajo. Una CPU ARM moderna puede consumir cientos de milivatios por core con una carga típica y bajar a sólo unos cuantos milivatios en su estado de hibernación más bajo. En tal estado, aunque la CPU está inactiva, puede recibir una interrupción, despertarse y reanudar su anterior actividad muy rápidamente. Por lo tanto, un teléfono Android inactivo en su bolsillo usa muy poca energía, pero puede cobrar vida cuando recibe una llamada telefónica.
¿Cómo puede Android apagar los componentes individuales de un teléfono? ¿Cómo sabe cuándo es seguro apagar el almacenamiento flash y cómo ¿Sabe hacer eso antes de apagar el subsistema de E/S general? La respuesta es la gestión de energía a nivel de componentes, que es una infraestructura que comprende la relación entre los componentes y si cada componente está en uso. Para comprender la relación entre componentes, Android crea un árbol de dispositivos que representa la topología del dispositivo físico del teléfono. Por ejemplo, en una topología de este tipo, el almacenamiento flash y USB serían subnodos del Subsistema de E/S, que es un subnodo del bus del sistema, que a su vez conecta a la CPU. Para comprender el uso, cada componente está asociado con su driver de dispositivo, y el driver rastrea si el componente está en uso, por ejemplo, si hay E/S pendiente de flashear o si una aplicación tiene una referencia abierta a el subsistema de audio. Con esta información, Android puede administrar la energía de los componentes individuales del teléfono: si un componente no se utiliza, se gira apagado. Si todos los componentes del bus del sistema no se utilizan, el bus del sistema se apaga. Y si todos los componentes de todo el árbol de dispositivos no se utilizan, el sistema puede entrar en colapso de energía.
Con estas tecnologías, Android puede gestionar de forma agresiva su consumo de energía. Pero falta una pieza final de la solución: la capacidad de para evitar temporalmente que el sistema entre en colapso de energía. Considere un usuario jugando, viendo un video o esperando que se abra una página web. En todos estos casos, la aplicación necesita una forma de mantener el dispositivo activo, al menos temporalmente Los Wakelocks habilitan esta funcionalidad. Las aplicaciones adquieren y sueltan los wakelocks según sea necesario. Mientras una aplicación tiene un wakelock, el kernel evitará que el sistema entre en colapso de energía. Por ejemplo, mientras el Android Market actualiza una aplicación, mantendrá el bloqueo de activación para asegúrese de que el sistema no se suspenda hasta que se complete la actualización. Una vez completo, Android Market lanzará el wakelock, permitiendo que el sistema entre en colapso de energía. 
La administración de energía en general se basa en la administración de dispositivos, que es más complicado de lo que lo hemos mostrado hasta ahora. En el momento del arranque, el firmware del sistema analiza el hardware del sistema y crea un árbol de dispositivos en RAM. El kernel luego usa ese árbol de dispositivos para cargar drivers de dispositivos y administrar dispositivos. Muchas actividades adicionales de administración relacionadas con los dispositivos, que incluyen suma y resta de dispositivos de un sistema en ejecución ("conexión en caliente"), comprender y cambiar los estados de los dispositivos y la administración de energía. Las computadoras Modernas de uso general usan otro conjunto de código de firmware, configuración avanzada e interfaz de potencia (ACPI), para gestionar estos aspectos del hardware. ACPI es un estándar de la industria (http://www.acpi.info) con muchas funciones. Proporciona

Continuar navegando