Plan 9 de los Laboratorios Bell

Rob Pike

Dave Presotto

Sean Dorward

Bob Flandrena

Ken Thompson

Howard Trickey

Phil Winterbottom

1. USA

Motivación

A mediados de los 80, la tendencia en computación iba alejándose de los grandes sistemas centralizados de tiempo compartido y acercándose hacia redes de maquinas personales, más pequeñas, típicamente estaciones de trabajo UNIX. La gente estaba harta de las máquinas de tiempo compartido sobrecargadas y deseaba cambiar a sistemas pequeños, de auto-mantenimiento incluso aun perdiendo potencia de computación.

Cuando los microordenadores se hicieron más rápidos, incluso esta pérdida de potencia se recuperó y este es el estilo de trabajo que permanece todavía hoy.

En la loca carrera hacia los ordenadores personales, algunas de sus carencias fueron pasadas por alto. Primero el sistema operativo que ejecutaban, UNIX, es realmente un sistema de tiempo compartido, y ha tenido algunos problemas para adaptarse a ideas que nacieron despues de él. Los gráficos y las redes fueron elementos agregados sobre la marcha, y todavía permanecen como algo poco integrado y dificil de administrar.

Más importante, el enfoque inicial de tener máquinas privadas hizo dificil para las redes dar el servicio que antaño dieron los sistemas monolíticos. Los sistemas de tiempo compartido centralizaban la gestión y amortizaban costes y recursos; la computación personal fracturó, democratizó y últimamente amplificó los problemas administrativos. La elección de un sistema antiguo para ser ejecutado en máquinas personales dificultó las cosas.

Plan 9 nació a finales de los años 80, como un intento de tener ambas cosas: construir un sistema que fuera administrado centralizadamente y que fuese barato, usando modernos microordenadores como base. La idea era crear un sistema de tiempo compartido para estaciones de trabajo, pero de una manera nueva. Diferentes ordenadores podrían manejar diferentes tareas, pequeñas y baratas máquinas en oficinas que sevirían como terminales proporcionando acceso a recursos centralizados compartidos como servidores de computación o de almacenamiento. Para las máquinas centrales, la moda imperante de multiprocesadores de memoria compartida parecía un candidato obvio. La filosofía era parecida a la del Cambridge Distributed System [NeHe82] El objetivo inicial era crear un UNIX a base de sistemas pequeños, no un system a a base de pequeños UNIXes.

Los problemas con UNIX eran demasiado profundos para arreglarlos, pero algunas de sus ideas podían mantenerse. La mejor fué su uso de un sistema de ficheros para coordinar el nombre y el acceso a los recursos, incluso si estos, como los dispositivos, no habían sido tradados tradicionalmente como ficheros. Para Plan 9, adoptamos esta idea diseñando un protocolo a nivel de red llamado 9P, para permitir el acceso a sistemas remotos. Sobre él, construimos un sistema de nombres que permitiría a la gente y a sus máquinas construir vistas personalizadas de los recursos de la red. Aquí fué donde Plan 9 empezó a parecer diferente: un usuario de Plan 9 construye un entorno de computación personalizado y lo recrea donde lo desee, en lugar de realizar todo su trabajo en una máquina privada. Pronto quedó claro que este modelo era mucho más rico que el que habíamos previsto, y la idea de un espacio de nombres por proceso y recursos como sistemas de ficheros se extendieron a todo el sistema —to procesos, gráficos, incluso la red misma.

l

En 1989 el sistema era suficientemente sólido, tanto que para que algunos de nosotros se convirtió en el entorno de computación exclusivo. Esto significó poner en marcha algunos de los servicios y aplicaciones que habíamos usado en UNIX. Usamos esta oportunidad para revisitar algunas cuestiones, no solamente las propias del nucleo, que creíamos que UNIX no resolvía bien. Plan 9 tiene nuevos compiladores, lenguajes, librerías, sistemas de ventanas, y muchas nuevas aplicaciones. Muchas de las viejas herramientas fueron abandonadas, mientras que las que se mantuvieron fueron refinadas o reescritas.

¿Por qué abarcar tanto? La diferencia entre sistema operativo, librería y aplicación es importante para el investigador, pero no lo es para el usuario. Lo que importa es la funcionalidad limpia. Construyendo un sistema completamente nuevo, podíamos resolver problemas donde creíamos que debían ser resueltos. Por ejemplo, no hay un driver tty en el nucleo, ese es un trabajo del sistema de ventanas. En el mundo moderno, la computación multi-sistema y multi-arquitectura es esencial, pero los compiladores y herramientas usuales asumen que el programa se construye para ejecutarse localmente; necesitábamos replantear estas cuestiones.

Más importante aun, la prueba de un sistema es el entorno de computación que proporciona. Producir una forma más eficiente de ejecutar el viejo UNIX es tiempo perdido, estábamos más interesados en si las nuevas ideas sugeridas por la arquitectura subyacente fomentaban una forma de trabajar más efectiva. Así, aunque Plan 9 proporciona un entorno de emulación para ejecutar comandos POSIX, sólo es un módulo "concreto???" del sistema. La gran mayoría del software del sistema está desarrollado en el modo ‘nativo’ del entorno Plan 9.

Tener un sistema completamente nuevo tiene sus beneficios Primero, nuestro laboratorio tiene una amplia historia de creación experimental de periféricos. Para facilitar la escritura de drivers, queríamos un sistema que estuviese disponible en código fuente (algo que ya no garantizaba UNIX, aún en el laboratorio en el que había nacido). También queríamos redistribuir nuestro trabajo, lo que significaba que el software debía ser producido localmente. Por ejemplo, podríamos haber usado algunos compiladores de marca para nuestro sistema, pero incluso superando los problemas de la compilación cruzada, hubiésemos tenido dificultades distribuyendo el resultado.

Este documento sirve como visión general del sistema. Habla de la arquitectura desde las piezas más pequeñas hasta el entorno que ve el usuario. También sirve como introducción al resto del Manual del Programador del Plan 9, que le acompaña, donde se pueden encontrar más detalles sobre los temas tratados aquí.

Diseño

La vista del sistema está construida sobre tres principio. Primero, los recursos son nombrados y accedidos como ficheros en un sistema de ficheros jerárquico. Segundo, hay un protocolo estandar, llamado 9P, para acceder a esos recursos. Tercero, las distintas jerarquias proporcionadas por servicios diferentes se unen en un solo espacio de nombres jerárquico privado. Las unusuales propiedades de Plan 9 son consecuencia de la aplicación consistente y enérgica de estos principios.

Una instalación Plan 9 grande tiene un número de ordenadores conectados en red, cada uno proporcionando un tipo particular de servicio. Servidores multiprocesador compartidos proporcionan ciclos de computación, otras máquinas ofrecen espacio de almacenamiento. Estas máquinas están localizadas en una sala acondicionada y conectadas a redes de alto rendimiento. Redes de banda estrecha como Ethernet o ISDN conectan estos servidores a las estaciones de trabajo de la oficina y de casa llamadas terminales en la terminología de Plan 9. La figura 1 muestra esta disposición.

El estilo moderno de computación ofrece a cada usuario una estación de trabajo dedicada o PC. El enfoque de Plan 9 es diferente. Las distintas máquinas con pantalla, teclado y raton proporcionan acceso a los recursos de la red, de manera que son funcionalmente equivalentes, igual que las terminales conectadas a los viejos sistemas de tiempo compartido. Cuando alguien usa el sistema, sin embargo, la terminal es temporalmente personalizada para ese usuario. En lugar de personalizar el hardware, Plan 9 ofrece la habilidad de personalizar la visión del sistema que proporciona el software. Esta personalización se consigue dando nombres locales, personales a los recursos visibles de la red. Plan 9 proporciona el mecanismo para ensamblar una visión personal del espacio público con nombres locales para los recursos globalmente accesibles. Puesto que los recursos más importantes de la red son ficheros, el modelo de esta vista es orientado a ficheros.

El espacio de nombres local del cliente proporciona una forma de personalizar la vista de la red del usuario. Todos los servicios disponibles en la red exportan jerarquías de ficheros. Los importantes para el usuario son puestos juntos en un espacio de nombres personal, los que no tienen un interés inmediato son ignorados. Este es un estilo distinto de uso de la idea de un ‘espacio de nombres uniforme global’. En Plan 9, hay nombres conocidos para servicios y nombres uniformes para ficheros exportados por esos servicios, pero la vista es enteramente local. Como analogía, considérese la diferencia entre la frase ‘mi casa’ y el domicilio real del hablante. Cualquiera puede usarlo, pero lo primero es más facil de decir y tiene perfecto sentido en la conversación. También cambia de significado dependiendo de quién lo diga, pero incluso eso no produce ninguna confusión. De modo similar, en Plan 9 el nombre /dev/cons siempre se refiere a la terminal del usuario y /bin/date la versión correcta del comando data a ejecutar, pero qué ficheros representan estos nombres dependerá de circunstancias como la arquitectura de la máquina. date. Plan 9 tiene espacios de nombres locales que obedecen a convenciones establecidad globalmente; y que son las que garantizan el comportamiento correcto en presencia de nombres locales.

El protocolo 9P es estructurado como un conjunto de transacciones que envia una solicitud desde un cliente a un servidor (local o remoto) y que devuelve un resultado. 9P controla sistemas de ficheros, no solamente ficheros: incluye procedimientos para resolver nombres de fichero y recorrer la jerarquía de nombres proporcionada por el servidor. Por otra parte, el espacio de nombres del cliente es mantenido únicamente por el sistema del cliente, no por o en el servidor, a diferencia de sistemas como Sprite [OCDNW88]. También, el acceso a ficheros es a nivel de bytes, no de bloques, lo que distingue a 9P de protocolos como NFS o RFS. Un documento de Welch compara estructuras de sistemas de ficheros de red de Sprite, NFS y Plan 9 [Welc94].

Este enfoque fué diseñado con los ficheros tradicionales en mente, pero puede ser extendido a cualquier tipo de recursos. Los servicios de Plan 9 que exportan jerarquías de ficheros incluyen dispositivos E/S, servicios de backup, el sistema de ventanas, interfaces de red, y muchos otros. Un ejemplo es el sistema de ficheros de procesos, /proc, que proporciona una forma de examinar y controlar procesos activos. Sistemas precursores tuvieron ideas similares [Kill84], pero Plan 9 lleva la metáfora de fichero mucho más alla [PPTTW93]. El modelo de sistema de ficheros se entiende bien, tanto por los programadores como por los usuarios, así que los servicios que presentan interfaces tipo fichero son fáciles de crear, de entender y de usar. Los ficheros vienen ya, por acuerdo general, con reglas para la protección, el nombre y el acceso local y remoto, así que los servicios construidos en base a ellos están listos para un sistema distribuido. (Esto es diferente de los modelos ‘orientados a objetos’, donde estas cuestiones deben plantearse desde cero para cada clase u objeto) Estas ideas en acción se ilustran con ejemplos en la siguiente sección.

La vista a nivel de comando

Plan 9 está pensado para ser usado desde una máquina con una pantalla corriendo un sistema de ventanas. No tiene el concepto de ‘teletipo’ en el sentido UNIX. El manejo de teclado del sistema es rudimentario, pero una vez que el sistema de ventanas, 8 1/2 [Pike91] está corriendo, el texto puede ser editado con operaciones de cortar y pegar, no solamente en la linea de entrada actual. Las capacidades de edición de texto de 8 1/2 son suficientemente potentes como para desplazar capacidades especiales como la historia de la shell, el paginado y el scroll, y los editores de correo. Las ventanas de 8 1/2 no soportan el direccionamiento por cursor, y excepto por un emulador de terminal para simplificar la conexión a los sistemas tradicionales, no hay direccionamiento por cursor en Plan 9.

Cada ventana se crea en un espacio de nombres separado. Los ajustes hechos al espacio de nombres en una ventana no afectan a otras ventanas o programas, haciendo seguro experimentar con modificaciones locales, por ejemplo, para sustituir ficheros desde el sistema de ficheros de volcado cuando se hace debugging. Una vez que se termina, la ventana puede cerrarse, y cualquier rastro de la operación desaparecerá. Similares argumentos se aplican al espacio privado que tiene cada ventana para variables de entorno, notas (análogas a señales en UNIX), etc.

Cada ventana se crea ejecutando una aplicación, como una shell, con la entrada y la salida estandar conectadas al texto editable de la ventana. Cada ventana tiene un bitmap privado y multiplexa el acceso al teclado, el ratón, y cualquier otro recurso gráfico a través de ficheros como /dev/mouse, /dev/bitblt, y /dev/cons (analogos a /dev/tty de UNIX). Estos ficheros son proporcionados por 8 1/2, que está implementado como un servidor de ficheros. A diferencia de X windows, donde una nueva aplicación típicamente crea una nueva ventana para correr en ella, en 8 1/2 las aplicaciones gráficas usualmente corren en la ventana desde la que arrancan. Es posible por eficiencia para una aplicación crear una nueva ventana, pero ese no es el estilo del sistema. De nuevo en contraste con X, en donde una aplicación remota hace una llamada de red al servidor X para empezar a correr, una aplicación remota 8 1/2 ve los ficheros mouse, bitblt, y cons para la ventana como de costumbre en /dev; no sabe si los ficheros son locales. Solo lee y escribe en ellos para controlar la ventana; la conexión de red ya está ahí y además multiplexada.

El estilo de uso deseado es correr aplicaciones interactivas como el sistema de ventanas y el editor de texto en el terminal y ejecutar aplicaciones de alto consumo de proceso o de espacio de almacenamiento en servidores remotos. Diferentes ventanas pueden estar ejecutando programas en diferentes máquinas sobre diferentes redes, pero haciendo el espacio de nombres equivalente en todas las ventanas, esto es transparente, los mismos comandos y recursos están disponibles, con los mismos nombres, dondequiera que se realice la computación.

El set de comandos de Plan 9 es similar al de UNIX. Los comandos se dividen en varias clases. Algunos son programas nuevos para tareas viejas: programas como ls, cat, y who tienen nombre y funciones familiares, pero son implementaciones nuevas, más simples Who, por ejemplo, es un script de shell, mientras ps consiste en 95 lineas de código en C. Algunos comandos son esencialmente los mismos que sus antecesores UNIX: awk, troff, y otros, han sido convertidos a ANSI C y extendidos para manejar Unicode, pero todavía siguen siendo los mismos Algunos son programas totalmente nuevos para viejos problemas: el shell rc, editor de textos sam, debugger acid, y otros, desplazan a herramientas UNIX bien conocidas con tareas similares. Finalmente, aproximadamente la mitad de los comandos son nuevos.

La compatibilidad no era un requerimiento del sistema. Donde la versión anterior parecía suficientemente buena, se mantenía. Cuando no se reemplazaba.

El servidor de ficheros

Un servidor de ficheros central almacena los ficheros permanentes y los presenta a la red como una jerarquía exportada usando 9P. El servidor es un sistema independiente, accesible solo a través de la red, diseñado para hacer un bien una sola cosa. No ejecuta procesos de usuario, solo un conjunto fijo de rutinas compiladas en la imagen de arranque. En lugar de un conjunto de discos o sistemas de ficheros separados, la jerarquía principal exportada por el servidor es un solo árbol, que representa ficheros en varios discos. Esta jerarquía es compartida por muchos usuarios a los largo de un area amplia en una variedad de redes. Otros árboles de ficheros exportados por el servidor incluyen sistemas de propósito especial, como almacenamiento temporal, como explicaremos más adelante y servicio de backup.

El servidor de ficheros tiene tres niveles de almacenamiento. El servidor central de nuestra instalación tiene sobre 100 megabytes de buffers de memoria, 27 gigabytes de discos y 350 gigabytes de almacenamiento en masa, en un jukebox de write-once-read-many (WORM). El disco es un caché para el WORM y la memoria es un caché para el disco; cada uno es más rápido, y ve un orden de magnitud más de tráfico que el nivel que cachea. Los datos direccionables en el sistema de ficheros pueden ser superiores al tamaño de los discos magnéticos, puesto que estos solo son un caché; nuestro servidor principal tiene sobre 40 gigabytes de almacenamiento activo.

La característica más inusual del sistema de ficheros viene del uso del dispositivo WORM para el almacenamiento definitivo. Cada mañana, a las 5 en punto, un dump del sistema de ficheros ocurre automáticamente. El sistema es congelado y todos los bloques modificados desde el último volcado son puestos a la cola para ser escritos en el WORM. Una vez que los bloques están en la cola, el servicio se restablece, y la raiz del sistema de ficheros volcado aparece en una jerarquía de todos los volcados que se han realizado hasta el momento, nombrados por su fecha. Por ejemplo, el directorio /n/dump/1995/0315 es la raiz del directorio de una imagen del sistema de ficheros tal como aparecía en la mañana del 15 de Marzo de 1995. Se tarda pocos minutos en poner en cola todos los bloques, pero el proceso de copia de los bloques al WORM, que corre en background, puede tardar horas.

Hay dos maneras de usar el sistema de ficheros de volcado. La primera es por los usuarios, que pueden hojear el sistema de ficheros volcado directamente, o enganchar piezas del mismo en su espacio de nombres. Por ejemplo, para tracear un error, lo más directo es compilar lo que se tenía hace tres meses, o linkar un programa con la librería de ayer. Con instantáneas diarias de todos los ficheros, es fácil encontrar cuándo un cambio determinado fué hecho, o qué cambios se hicieron después de una fecha. La gente se siente libre de hacer grandes cambios especulativos en los ficheros, seguros de que pueden volver atrás con un simple comando de copia. No hay un sistema de backup como tal; en su lugar, puesto que los volcados estan en el espacio de nombres, los problemas de backup pueden resolverse con herramientas estandar como cp, ls, grep, y diff.

El otro (muy raro) uso es hacer una copia de seguridad del sistema. En caso de desastre, el sistema de ficheros activo puede ser inicializado desde un volcado, borrando el caché del disco y poniendo la raiz del sistema activo como una copia de la raíz volcada. Aunque fácil de hacer, no debe tomarse a la ligera: además de perder cualquier cambio realizado en la fecha del volcado, este método de recuperación puede hacer el sistema muy lento. El caché debe ser recargado desde el WORM, que es mucho más lento que los discos magnéticos. El sistema de ficheros tardará un par de días en recargar el conjunto de trabajo y recuperar su rendimiento máximo

Los permisos de acceso de los ficheros en el volcado son los mismos que eran en el momento en que se hizo el volcado. Utilidades normales tienen permisos normales en el volcado sin ningún cuidado especial. El sistema de ficheros de volcado es, sin embargo, de solo lectura, lo que significa que los ficheros del volcado no pueden ser reescritos, sean cuales sean sus bits de permisos; de hecho, puesto que los directorios son parte de una estructura de solo lectura, incluso los permisos no se les pueden cambiar.

Una vez que un fichero es escrito en el WORM, no puede ser borrado, así que nuestros usuarios nunca verán mensajes del tipo ‘‘por favor, borre ficheros’’ y no existe el comando df. Vemos el jukebox WORM como un recurso ilimitado. La única cuestión es cuánto tiempo tardaremos en llenarlo. Nuestro WORM ha servido a una comunidad de unos 50 usuarios durante cinco años y ha absorbido backups diariosr, consumiendo un total del 65% del espacio del jukebox. En todo ese tiempo, el fabricante ha mejorado la tecnología, doblando la capacidad de los discos individuales. Si nos hubiésemos actualizado, tendríamos más espacio libre que en el jukebox vacio original. La tecnología ha creado espacio más rápido de lo que nosotros lo hemos podido utilizar.

Servidores de ficheros inusuales

Plan 9 se caracteriza por una variedad de servidores que ofrecen un interfaz de tipo fichero para servicios inusuales. Muchos de estos estan implementados por procesos de nivel de usuario, aunque la distinción no es importante para sus clientes; que un servicio sea proporcionado por el nucleo, por un proceso de usuario, o por un servidor remoto es irrelevante para la forma en que es usado. Hay docenas de estos servidores; in esta sección presentamos tres representativos.

Quizá el servidor de ficheros más extraordinario en Plan 9 es 8 1/2, el sistema de ventanas. Se comenta en profundidad en otro documento [Pike91], pero merece una breve explicación aqui. 8 1/2 proporciona dos interfaces: al usuario sentado en la terminal, le ofrece un estilo tradicional de interacción con múltiples ventanas, cada una corriendo una aplicación, todo controlado por el teclado y el ratón. A los programas cliente, la vista que ofrece es también bastante tradicional: los programas corriendo en una ventana ven un gconjunto de ficheros en /dev con nombres como mouse, screen, y cons. Los programas que quieren mostrar texto en su ventana escriben en /dev/cons; para leer el ratón leen /dev/mouse. En el estilo Plan 9, los gráficos bitmap son implementados proporcionando un fichero /dev/bitblt en el que los clientes escriben mensajes codificados para ejecutar operaciones gráficas, como bitblt (RasterOp). Lo que es inusual es cómo se hace esto: 8 1/2 es un servidor de ficheros, sirviendo ficheros en /dev a los clientes que corren en cada ventana. Aunque cada ventana parece igual para su cliente, cada una tiene un conjunto de ficheros diferente en /dev. 8 1/2 multiplexa el acceso de sus clientes a los recursos de la terminal sirviendo múltiples conjuntos de ficheros. A cada cliente le da un espacio de nombres con un conjunto de ficheros distinto que se comporta igual que en las demás ventanas. Este sistema tiene muchas ventajas. Una es que 8 1/2 sirve los mismos ficheros que necesita para su propia implementación — multiplexa su propio interfaz — de modo que puede correr recursivamente como cliente de sí mismo. También, considérese la implementación de /dev/tty en UNIX, que requiere un código especial en el nucleo para redireccionar llamadas open al dispositivo apropiado. En lugar de eso, en 8 1/2, el servicio equivalente aparece automáticamente: 8 1/2 sirve /dev/cons como una de sus funciones básicas, no hay que hacer nada extra. Cuando un program quiere leer del teclado, abre /dev/cons, pero es un fichero privado, no uno compartido con propiedades especiales. De nuevo, los espacios de nombres locales hacen esto posible; las convenciones sobre la consistencia de los ficheros lo hacen natural.

8 1/2 tiene una característica única que su diseño hace posible. Como está implementado como un servidor de ficheros, tiene la capacidad de posponer la respuesta a las solicitudes recibidas en una ventana determinada. Este comportamiento es conmutado por una tecla reservada. Pulsandola una vez, se suspende la lectura desde la ventana, pulsándola otra vez, se retoma la lectura normal, que absorve cualquier texto que haya sido preparado, linea a linea. Esto permite al usuario editar una entrada de texto de varias lineas en la pantalla antes de que la aplicación la reciba, obviando la necesidad de invocar un editor separado para preparar texto como mensajes de correo. Una propiedad relacionada es que las lecturas son contestadas directamente de la estructura de datos que define el texto en pantalla: el texto puede ser editado hasta que el salto de linea final lo hace legible para el cliente. Incluso entonces, hasta que la linea es leida, el texto que el cliente leerá puede ser cambiado. Por ejemplo, después de teclear

No hay comando ftp en Plan 9. En su lugar, un servidor de ficheros de nivel usuario llamado ftpfs llama al sitio FTP, entra como el usuario, y usa el protocolo FTP para examinar los ficheros en el directorio remoto. Para el usuario local, ofrece una jerarquía de ficheros enganchada a /n/ftp en el espacio de nombres local, haciendo un espejo de los contenidos del sitio FTP. En otras palabras, traduce el protocolo FTP a 9P, para ofrecer acceso Plan 9 a sitios FTP. La implementación es delicada: ftpfs debe hacer un cacheo sofisticado por razones de eficiencia, y usar heurística para decodificar la información del directorio remoto. Pero el resultado merece la pena: todas las herramientas de manejo de ficheros locales como cp, grep, diff, y, por supuesto ls están disponibles para ficheros servidos por FTP exactamente igual que si fuesen ficheros locales. Otros sistemas, como Jade y Prospero, han explotado la misma oportunidad [Rao81, Neu92], pero debido a los espacios de nombres locales y a la sencillez de implementación de 9P, este enfoque cae de forma más natural en Plan 9 que en otros entornos.

Un servidor, exportfs, es un proceso de usuario que toma una porción de su propio espacio de nombres y lo hace disponible para otros procesos traduciendo solicitudes 9P a llamadas al sistema del nucleo de Plan 9. La jerarquía de ficheros que exporta puede contener ficheros de múltiples servidores. Exportfs es usualmente ejecutado como servidor remoto, arrancado por un programa local, que será import o cpu. Import hace una llamada de red a la máquina remota, inicia exportfs allí, y enlaza su conexión 9P al espacio de nombres local. Por ejemplo,

Configurabilidad y administración

La interconexión uniforme de componentes en Plan 9 hace posible configurar una instalación de muchas formas distintas. Un simple PC portatil puede funcionar como sistema Plan 9 autónomo; en el otro extremo, nuestra configuración tiene servidores CPU y servidores de ficheros y cantidad de terminales desde pequeños PC hasta estaciones de trabajo. Es este tipo de red amplia la que representa mejor cómo opera Plan 9.

El software de sistema es portable, y el mismo sistema operativo corre en todo el hardware. Excepto por el rendimiento, la apariencia del mismo en, digamos una estanción de trabajo SGI es el mismo que en cualquier portatil. Puesto que la computación y el servicio de ficheros estan descentralizados, y los terminales no tienen almacenamiento permanente, todos los terminales son funcionalmente idénticos. De esta manera, Plan 9 tiene una de las mejores propiedades de los viejos sistemas de tiempo compartido, en los que un usuario se sentaba frente a una máquina y veía el siempre mismo sistema. En la comunidad moderna de estaciones de trabajo, las máquinas tienden a ser poseidas por gente que las personaliza agregando información privada en su disco local. Rechazamos este estilo de uso, aunque el sistema mismo puede ser usado así. En nuestro grupo, tenemos un laboratorio con muchas máquinas de acceso público — una sala de terminales — y un usuario puede sentarse en cualquiera y trabajar.

Los servidores de ficheros centrales no solamente centralizan los ficheros, sino también la administración y el mantenimiento. De hecho, un servidor es el central, y mantiene todos los sistemas de ficheros; otros proporcionan almacenamiento extra, o estan disponibles para debugging u otros usos específicos, pero el software del sistema reside en una máquina. Esto significa que cada programa tiene una sola copia del código binario para cada arquitectura, de modo que es trivial instalar actualizaciones y resolver errores. También hay una sola base de datos de usuarios; no se necesita sincronizar distintos ficheros /etc/passwd. Por otra parte, depender de un solo servidor central limita el tamaño de una instalación.

Otro ejemplo del poder del servicio de ficheros centralizado es la forma en que Plan 9 administra la información de red. En el servidor central hay un directorio, /lib/ndb, que contiene toda la información necesaria para administrar la red local Ethernet y otras redes. Todas las máquinas usan la misma base de datos para hablar a la red; no hay necesidad e manejar un sistema de nombres distribuido, o mantener actualizados ficheros paralelos. Para instalar una nueva máquina en la Ethernet local, se elige un nombre, una dirección IP y se agrega todo a un solo fichero en /lib/ndb; todas las máquinas en la instalación podrán comunicarse con ella inmediatamente. Para empezar a funcionar, se conecta la máquina a la red, se enciende, y se usa BOOTP y TFTP para cargar el nucleo. Todo lo demás es automático.

Finalmente, el volcado automático del sistema de ficheros libera a todos los usuarios de la necesidad de mantener sus sistemas, mientras proporciona fácil acceso a los backups sin cintas, comandos especiales ni personal de soporte. Es difícil exagerar la mejora en el estilo de vida que proporciona este servicio.

Plan 9 ejecuta una variedad de hardware sin restringir el modo de configurar la instalación. En nuestro laboratorio, hemos elegido usar servidores centrales puesto que amortizan los costes y la administración. Una señal de que esto es una buena decisión es que nuestras baratas terminales continúan siendo lugares confortables para trabajar cinco años después, mucho más que estaciones de trabajo que deben proporcionar un entorno de computación completo. No obstante, hemos actualizado las máquinas centrales, así que la computación disponible incluso desde las antiguas terminales de Plan 9 mejora con el tiempo. El dinero ahorrado al evitar la actualización regular de terminales se ha gastado en cambio en los más modernos y rápidos servidores multiprocesador. Estimamos que aproximadamente por la mitad del coste de las estaciones de trabajo en red proporcionamos acceso general a máquinas más potentes.

Programación en C

Las utilidades de Plan 9 están escritas en varios lenguajes. Algunos son scripts de la shell, rc [Duff90]; otras están escritas en un nuevo lenguaje concurrente parecido a C llamado Alef [Wint95], descrito más adelante. La gran mayoría, sin embargo, esta escrita en un dialecto de ANSI C [ANSIC]. De estos, muchos son programas totalmente nuevos, pero algunos estaban escritos en pre-ANSI C para nuestro sistema de investigación UNIX [UNIX85]. Estos se han actualizado a ANSI C y corregidos para portabilidad y limpieza.

El dialecto de C de Plan 9 tiene algunas extensiones menores, descritas en [Pike95], y algunas grandes restricciones. La restricción más importante es que el compilador exige que todas las funciones tengan prototipos ANSI y todas las llamadas a funciones deben aparecer en el ámbito de una declaración prototipada de la función. Como regla de estilo, la declaración prototipada se coloca en el fichero de cabecera incluido por todos los ficheros que llaman a la función. Cada librería de sistema tiene un fichero de cabecera asociado, que declara todas las funciones de la librería. Por ejemplo, la librería estandar de Plan 9 se llama libc, así que todos los ficheros fuentes en C incluyen <libc.h>. Estas reglas garantízan que todas las funciones sean llamadas con argumentos que tengan los tipos experados — algo que no ocurría en los programas pre-ANSI C —

Otra restricción es que los compiladores de C aceptan solo un subconjunto de las directivas de preprocesador requeridas por ANSI. La omisión principal es #if, porque creemos que nunca es necesaria y que a menudo se abusa de ella. Además, su efecto se consigue mejor por otros medios. Por ejemplo, un #if usado para conmutar una característica en tiempo de compilación puede ser escrito como una sentencia if normal, apoyándose en la carácterística de eliminación de código muerto, que proporcina un tiempo de compilación constante y lo descarta del código objeto.

La compilación condicional, incluso con #ifdef, es escasamente usada en Plan 9. Los únicos #ifdefs dependientes de la arquitectura en el sistema están en rutinas de bajo nivel, en la librería gráfica. En su lugar, evitamos estas dependencias o, cuando es necesario las aislamos en ficheros o librerías separados. Además de hacer el código difícil de leer, los #ifdefs hacen imposible conocer qué fuente es compilada en el binario, o si el fuente protegido por ellos será compilado o funcionará adecuadamente. Hacen más difícil mantener el software.

La librería estandar de Plan 9 coincide bastante con ANSI C y POSIX [POSIX], pero se diverge en lo que respecta a los objetivos o implementación de Plan 9. Cuando la semántica de una función cambia, le cambiamos también el nombre. Por ejemplo, en lugar del creat, de UNIX, Plan 9 tiene la función create que toma tres argumentos, los dos originales mas un tercero, que como el segundo de open, define si el descriptor de fichero devuelto será abierto para lectura, escritura o ambas. Este diseño viene forzado por la forma en la que 9P implementa la creación, pero tambien simplifica el uso normal de create para inicializar un fichero temporal.

Otra diferencia con ANSI C es que Plan 9 usa un set de caracteres de 16 bits llamado Unicode [ISO10646, Unicode]. Aunque nos detuvimos poco antes de conseguir la total internacionalización, Plan 9 trata la representación de todos los idiomas más importantes de un modo uniforme en todo su software. Para simplificar el intercambio de texto entre programas, los caracteres se empaquetan en un flujo de bytes por medio de una codificación que nosotros diseñamos, llamada UTF-8, que está siendo ahora aceptada como un estandar [FSSUTF]. Tiene varias propiedades atractivas, incluyendo la independencia de orden de byte, la compatibilidad retroactiva con ASCII, y la facilidad de implementación.

Hay muchos problemas Adaptar software existente a un conjunto de caracteres mayor con una codificación que representa caracteres con un número variable de bytes trae consigo muchos problemas. ANSI C trata algunos de ellos, pero no consigue resolverlos todos. No selecciona una codificación para el conjunto de caracteres, y no define las rutinas necesarias de E/S. Más aún, las funciones que define tienen problemas de diseño. Dado que el estandar dejaba demasiados problemas sin resolver, decidimos crear nuestro propio interfaz. Un documento aparte tiene los detalles [Pike93].

Cierta clase de programas Plan 9 no entran en las convenciones explicadas en esta sección. Son los programas importados de y mantenidos por la comunidad UNIX; tex es un ejemplo representativo. Para evitar reconvertir estos programas en cada nueva versión, construimos un entorno de porting, llamado ANSI C/POSIX Environment, o APE [Tric95]. APE comprende un conjunto separado de ficheros de cabecera, librerías y comandos, conformes a las estrictas especificaciones ANSI C y POSIX. Para portar software de red como X Windows, fué necesario agregar algunas extensiones a estas especificaciones, como las funciones de red BSD.

Portabilidad y Compilación

Plan 9 es portable a través de una variedad de arquitecturas de procesador. Dentro de una sola sesión de computación, es normal usar varias arquitecturas, quizá el sistema de ventanas corra en un procesador Intel, conectado a un servidor de CPU basado en MIPS, con ficheros residentes en una SPARC. Para que esta heterogeneidad sea transparente, debe haber convenciones respecto al intercambio de datos entre programas; para que el mantenimiento sea sencillo debe haber convenciones respecto a la compilación cruzada.

Para evitar problemas de orden de byte, los datos se comunican entre programas como texto, siempre que resulte práctico. A veces, sin embargo, la cantidad de datos es suficientemente alta como para que se necesite un formato binario; estos datos se comunican como un flujo de bytes con una codificación predefinida para valores multi-byte. En el caso raro en que un formato sea tan complejo como para ser definido como una estructura, la estructura nunca se comunica como una unidad, sino que se descompone en campos individuales, se codifica en un flujo de bytes ordenados y se reensambla en el receptor. Estas convenciones afectan a todos los datos, desde el nucleo o información de estado de programas de aplicación hasta ficheros objeto intermedios generados por el compilador.

Los programas, incluido el nucleo, a menudo presentan sus datos a través de un interfaz de sistema de ficheros, un mecanismo de acceso que es inherentemente portable. Por ejemplo, el reloj del sistema es representado mediante un número decimal en el fichero /dev/time; la función de librería time (no hay una llamada del sistema time) lee el fichero y lo convierte en binario. De modo parecido, en lugar de codificar el estado de un proceso de una aplicación en una serie de flags y bits en memoria privada, el nucleo presenta una cadena de texto en el fichero llamado status en el sistema de ficheros /proc asociado a cada proceso. El comando ps en Plan 9 es trivial: muestra los contenidos de los ficheros de estado deseados después de un ligero formateo; más aún, después de hacer

Cada arquitectura soportada tiene su propio compilador y linker. Los compiladores de C y Alef producen ficheros intermedios que están codificados de manera portable; los contenidos son únicos para la arquitectura destino, pero el formato de los ficheros es independiente del tipo de procesador que compile. Cuando un compilador para una arquitectura dada es compilado en otro tipo de procesador y luego usado para compilar un programa allí, el código intermedio producido será idéntico al producido en el procesador nativo. Desde la perspectiva del compilador, cada compilación es una compilación cruzada.

Aunque el linker de cada arquitectura acepta solamente ficheros intermedios producidos por compiladores para esa arquitectura, esos ficheros pueden haber sido generados por un compilador ejecutado en otro tipo de procesador. Por ejemplo, es posible correr un compilador MIPS en un 486, y luego usar un linker MIPS en un SPARC para producir un ejecutable MIPS.

Puesto que Plan 9 corre en una variedad de arquitecturas, incluso en una sola instalación, diferenciar compiladores y nombres intermedios simplifica el desarrollo multi-arquitectura en un solo arbol de fuentes. El compilador y el linker para cada arquitectura tienen nombres únicos, no hay un comando cc Los nombres son derivados de concatenar una letra asociada a la arquitectura destino con el nombre del compilador o del linker. Por ejemplo, el caracter ‘8’ corresponde a los procesadores x86 de Intel; el compilador de C se llama 8c, el compilador de Alef 8al, y el linker 8l. Similarmente, los ficheros intermedios tienen como sufijo .8, y no .o.

El programa de construcción de Plan 9 mk, que es un pariente de make, lee los nombres de la arquitectura actual y de la destino de variables de entorno llamadas $cputype y $objtype. Por defecto, el destino es el procesador actual, pero poniendo el valor de $objtype con el nombre de otra arquitectura antes de invocar mk el resultado es una construcción cruzada:

Programación paralela

El soporte para programación paralela de Plan 9 tiene dos aspectos. Primero, el nucleo proporciona un modelo simple de proceso y unas cuantas llamadas al sistema cuidadosamente diseñadas para la sincronización y la compartición. Segundo, un nuevo lenguaje de programación paralela, llamado Alef que soporta la programación concurrente. Aunque es posible escribir programas paralelos en C, Alef es el lenguaje más adecuado para ello.

Hay una tendencia en los nuevos sistemas operativos a implementar dos clases de procesos: los procesos normales estilo UNIX y los hilos ligeros. En lugar de esto, Plan 9 proporciona una sola clase de procesos pero permite un control preciso de la compartición entre procesos de recursos como memoria o descriptores de ficheros. Una sola clase de procesos es un enfoque más viable en Plan 9, puesto que el nucleo tiene un interfaz eficiente de llamadas al sistema y una creación y planificación de procesos eficiente.

Los programas paralelos tienen tres requerimientos básicos: manejo de recursos compartido entre procesos, un interfaz con el planificador, y una sincronización precisa mediante ‘bloqueos giratorios’???????. En Plan 9, los procesos se crean usando la llamada del sistema rfork Rfork toma un solo argumento, un vector de bits que especifica cuál de los recursos del proceso padre deben ser compartidos, copiados o creados de nuevo en el proceso hijo. Los recursos controlados por rfork incluyen el espacio de nombres, el entorno, la tabla de descriptores de ficheros, segmentos de memoria, y notas (equivalentes a señales en UNIX). Uno de los bits controla si rfork creará un proceso nuevo; si el bit está en off, las modificaciones resultantes de los recursos ocurrirán en el proceso que hace la llamada. Por ejemplo, un proceso llama rfork(RFNAMEG) para desconectar su espacio de nombres del de su padre. Alef usa un fork de grano fino, en el que todos los recursos, incluyendo memoria, son compartidos entre el padre y el hijo, de forma análoga a como se crean hilos del nucleo en muchos sistemas.

Algo que demuestra que rfork es el modelo correcto es la variedad de formas en que es utilizado. Aparte del uso canónico de la rutina de librería fork, es difícil encontrar dos llamadas a rfork con el mismo conjunto de bits; los programas lo usan para crear muchas formas distintas de compartición y de asignación de recursos. Un sistema con solo dos tipos de procesos — procesos normales e hilos — no puede manejar esta variedad.

Hay dos formas de compartir memoria. Primero, un flag a rfork hace que todos los segmentos de memoria del padre sean compartidos con el hijo (excepto la pila, que es

???????? forked copy-on-write regardless). ???????? causes all the memory segments of the parent to be shared with the child (except the stack, which is forked copy-on-write regardless).

Alternativamente, un segmento nuevo de memoria puede enlazarse usando la llamada del sistema segattach ; este segmento será siempre compartido entre padre e hijo.

La llamada rendezvous proporciona una forma de sincronizar procesos. Alef la usa para implementar canales de comunicación, colas de bloqueo, bloqueos de múltiple lector/escritor, y el mecanismo de dormir y despertar. Rendezvous toma dos argumentos, una etiqueta y un valor. Cuando un proceso llama a rendezvous con una etiqueta, se duerme hasta que otro proceso presenta una etiqueta coincidente. Cuando un par de etiquetas coinciden, los valores se intercambian entre ambos procesos y ambas llamadas rendezvous retornan. Esta primitiva es suficiente para implementar el conjunto completo de rutinas de sincronización.

Finalmente, se proporcionan bloqueos giratorios por una librería dependiente de cada arquitectura a nivel usuario. La mayoría de los procesadores proveen instrucciones atómicas de test y set que pueden ser usadas para implementar bloqueos. Una excepción notable es el MIPS R3000, así que la seria SGI Power de multiprocesadores tienen un hardware de bloqueo especial en el bus. Los procesos de usuario ganan acceso al bloqueo de hardware mapeando páginas de bloqueos hardware en su espacio de direcciones usando la llamada segattach

Un proceso de Plan 9 en una llamada del sistema se bloqueará sin tener en cuenta su ‘peso’. Esto quiere decir que cuando un programa desea leer desde un dispositivo lento sin bloquear el cálculo completo, debe bifurcar un proceso para que lea por él. La solución es arrancar un proceso satélite que haga la E/S y envíe la respuesta al programa principal a través de memoria compartida o quizas de un pipe. Esto suena complejo, pero funciona fácil y eficientemente en la práctica; de hecho, la mayoría de aplicaciones interactivas de Plan 9, incluso las relativamente ordinarias escritas en C, como el editor de texto Sam [Pike87], corren como programas multiproceso.

El soporte del nucleo para programación paralela en Plan 9 consiste en unos cuantos cientos de lineas de código portable; unas cuantas primitivas simples permiten que los problemas se manejen limpiamente desde el nivel de usuario. La creación y manejo de procesos de E/S esclavos puede ser escrita en unas pocas lineas de Alef, proporcionando las bases para un medio consistente de multiplexado de flujos de datos entre procesos arbitrarios. Más aún, implementar eso en un lenguaje, en lugar de en el nucleo asegura una semántica consistente entre todos los dispositivos y proporciona una primitiva de multiplexado más general. Compárese esto con la llamada del sistema de UNIX select select se aplica solamente a un conjunto restringido de dispositivos, regula un estilo de multiprogramación en el nucleo, no es extesible a través de redes, es difícil de implementar y es difícil de usar.

Otra razón por la que la programación paralela es importante en Plan 9 es que los servidores de fichero multi-hilo de nivel usuario son la forma preferida de implementar servicios. Ejemplos de estos servicios incluyen el entorno de programación Acme [Pike94], la herramienta de exportación de espacios de nombres exportfs [PPTTW93], el demonio de HTTP, y los servidores de nombres de red cs y dns [PrWi93].

????????????? Aplicaciones complejas como Acme demuestran que un soporte cuidadoso por parte del sistema operativo puede reducir la dificultad de escribir aplicaciones multi-hilo sin mover las primitivas de hilos y de sincronización al nucleo.

Complex applications such as Acme prove that careful operating system support can reduce the difficulty of writing multi-threaded applications without moving threading and synchronization primitives into the kernel. ????????????

Implementación de espacios de nombres

Los procesos de usuario construyen espacios de nombres usando tres llamadas del sistema: mount, bind, y unmount. La llamada mount engancha un arbol servido por un servidor de ficheros al espacio de nombres actual. Antes de llamar a mount, el cliente debe (por medios externos) adquirir una conexión con el servidor en forma de un descriptor de fichero que puede ser leido y escrito para transmitir mensajes 9P. Este descriptor de fichero representa un pipe o una conexión de red.

La llamada mount engancha una nueva jerarquía al espacio de nombres existente. La llamada bind por otra parte, duplica una parte del espacio de nombres en otro punto del mismo espacio. La llamada unmount permite retirar componentes.

Con el uso de bind o mount, pueden apilarse múltiples directorios en un solo punto del espacio de nombres. En la terminología de Plan 9, esto es una union de directorios y se comporta como la concatenación de los directorios que la constituyen. Un argumento de bind y de mount especifica la posición del nuevo directorio en la unión, permitiendo a los nuevos elementos agregarse al inicio de la unión o bien reemplazar la jerarquía completa. Cuando se realiza una búsqueda de un fichero en una unión de directorios, cada componente de la unión se busca por turno, y se toma el primero que coincida; del mismo modo, cuando se lee una unión de directorios, los contenidos de cada directorio son leidos por turno. La unión de directorios es uno de las características de organización más ampliamente usadas de los espacios de nombres de Plan 9. Por ejemplo, el directorio /bin se crea como unión de /$cputype/bin (binarios de programas), /rc/bin (scripts de la shell), y quizá más directorios proporcionados por el usuario. Esta construcción hace innecesaria la variable $PATH

Una cuestión que surge con la unión de directorios es cuál elemento de la unión recibe un fichero recien creado. Después de varios diseños, decidimos lo siguiente. Por defecto, los directorios de una unión no aceptan ficheros nuevos, aunque la llamada del sistema create aplicada a un fichero existente tiene éxito normalmente. Cuando un directorio es agregado a una unión, una bandera en bind o en mount habilita el permiso de creación (una propiedad del espacio de nombres) en ese directorio. Cuando un fichero está siendo creado con un nombre nuevo en la unión, es creado en el primer directorio de la unión con permiso de creación; si esa creación falla, el create falla. Este esquema permite el uso común de colocar un directorio privado en alguna parte de una unión de directorios públicos, mientoras que permite la creación solamente en el directorio privado.

Por convenio, los sistemas de ficheros de dispositivos del nucleos están enlazados al directorio /dev pero para iniciar el proceso de construcción de espacio de nombres, es necesario tener una notación que permita acceso directo a los dispositivos sin un espacio de nombres existente. El directorio raíz del árbol servido por un driver de dispositivo puede ser accedido usando la sintaxis #c, donde c es un carácter único (típicamente una letra) que indentifica el tipo de dispositivo. Drivers de dispositivo simples sirven un directorio de un solo nivel que contiene unos pocos ficheros. Como ejemplo, cada puerto serie se representa por un fichero de datos y otro de control.

Es el uso universal del protocolo 9P el que conecta los componentes de Plan 9 para formar un sistema distribuido. En lugar de inventar un protocolo único para cada servicio como rlogin, FTP, TFTP, y X Windows, Plan 9 implementa servicios en términos de operaciones sobre objetos fichero, y luego utiliza un simple y bien documentado protocolo para intercambiar información entre equipos. A diferencia de NFS, 9P trata los ficheros como una secuencia de bytes en lugar de como bloques. Tambien, a diferencia de NFS, 9P guarda su estado: los clientes realizan llamadas a procedimientos remotos para establecer punteros a objetos en el servidor de ficheros remoto. Estos punteros se llaman identificadores de fichero, o fids. Todas las operaciones sobre ficheros devuelven un fid para identificar el objeto en el sistema de ficheros remoto.

El protocolo 9P define 17 mensajes, proporcionando medios para autenticar usuarios, navigar por los fids de una jerarquía de ficheros, copiar fids, realizar E/S, cambiar atributos de ficheros, y crear y borrar ficheros. Su especificación completa está en la sección 5 del Manual del Programador [9man]. Veamos el procedimiento para obtener acceso a la jerarquía de nombres proporcionada por un servidor. Se establece una conexión al servidor mediante un pipe o una conexión de red. Un mensaje inicial session realiza la autentificación bilateral entre cliente y servidor. Un mensaje attach conecta entonces un fid sugerido por el cliente a la raíz del arbol de ficheros del servidor El mensaje attach incluye la identidad del usuario que realiza el enganche; en adelante, todos los fids derivados del fid raíz tendrán los permisos asociados con ese usuario. Muchos usuarios pueden compartir la conexión, pero cada uno debe realizar un attach para establecer su identidad

El mensaje walk mueve un fid a través de un nivel de la jerarquía de ficheros. El mensaje clone toma un fid establecido y produce una copia que apunta al mismo fichero que el original. Su propósito es permitir el walking a un fichero del directorio sin perder el fid de ese directorio. El mensaje open bloquea un fid a un fichero específico de la jerarquía, comprobando los permisos de acceso y prepara el fid para E/S. Los mensajes read y write permiten E/S en desplazamientos arbitrarios en el fichero; el tamaño máximo transferido es definido por el protocolo. El mensaje clunk indica que el cliente ya no necesita un fid. El mensaje remove se comporta como clunk pero hace que el fichero asociado con ese fid sea borrado, y cualquier recurso asociado con el servidor sea liberado.

9P tiene dos formas: mensajes RPC enviados a un pipe o a una conexión de red y un interfaz procedural dentro del nucleo. Dado que los drivers del nucleo se pueden direccionar directamente, no se necesita pasar mensajes para comunicarse con ellos; en lugar de esto, cada transacción 9P es implementada mediante una llamada directa a un procedimiento. Para cada fid, el nucleo mantiene una representación local en una estructura de datos llamada channel, de modo que todas las operaciones sobre ficheros realizadas por el nucleo implican un canal conectado a ese fid. El ejemplo más simple son los descriptores de fichero de un proceso de usuario, que son índices a un array de canales. Una tabla del nucleo proporciona una lista de puntos de entrada correspondientes, uno a uno, con los mensajes de cada dispositivo. Una llamada del sistema como read desde el usuario se traduce en una o más llamadas a procedimientos a través de esa tabla, indexada por el caracter de tipo almacenado en el canal: procread, eiaread, etc. Cada llamada toma al menos un canal como argumento. Un driver especial del nucleo, llamado el driver mount traduce las llamadas a procedimientos a mensajes, es decir, convierte los procedimientos locales en remotos. En efecto, este driver especial viene a ser un proxy local para los ficheros servidos por un servidor remoto. El puntero al canal en la llamada local se traduce al fid asociado en el mensaje transmitido.

El driver mount es el único mecanismo RPC empleado por el sistema. La semántica de los ficheros proporcionados, en lugar de las operaciones realizadas sobre ellos, crea un servicio particular, como el comando cpu El driver mount demultiplexa los mensajes del protocolo entre clientes que comparten un mismo canal de comunicación con el servidor de ficheros. Para cada mensaje RPC saliente, el driver mount asigna un buffer etiquetado con un pequeño entero único, llamado tag. La respuesta al RPC es etiquetada con la misma tab, que es usada por el driver mount para hacer corresponder la repuesta con la solicitud.

La representación en el nucleo del espacio de nombres es llamada tabla de mount, y almacena una lista de enlaces entre canales. Cada entrada en la tabla de mount contiene un par de canales: un canal from y un canal to Cada vez que un walk tiene éxito moviendo un canal a un nuevo lugar en el espacio de nombres, la tabla mount se consulta para ver si el canal ‘from’ coincide con el nuevo nombre; si es así, el canal ‘to’ es clonado y sustituido por el original. Las uniones de directorios se implementan convirtiendo el canal ‘to’ en una lista de canales: un walk con éxito a una unión de directorios devuelve un canal ‘to’ que constituye la cabecera de una lista de canales, cada uno representando a un directorio de la unión. Si un walk falla al encontrar un fichero en el primer directorio de la unión, se sigue la lista, el siguiente componente es clonado, y se intenta un walk en él.

Cada fichero en Plan 9 es identificado unívocamente por un conjunto de enteros: el tipo de canal (usado como índice de la tabla de llamadas), el servidor o número de dispositivo, distinguiendo el servidor de otros del mismo tipo (decidido localmente por el driver), y un qid formado por un número de 32 bits llamado path y version. El path es un número de fichero único asignado por el driver o por el servidor de ficheros cuando el fichero es creado. El número de versión es actualizado cada vez que el fichero se modifica; tal como se describe en la siguiente sección, i puede usarse para mantener la coherencia en el caché entre clientes y servidores.

?????? El tipo y número de dispositivo son análogos a los números de dispositivo mayor y menor de UNIX; el quid es análogo al número-i. (nodo-i, i-node,...) ????????

The type and device number are analogous to UNIX major and minor device numbers; the qid is analogous to the i-number. ???????

El dispositivo y tipo conectan el canal a un driver, y el qid identifica el fichero dentro del dispositivo. Si el fichero obtenido en el walk tiene el mismo tipo, dispositivo y qid que una entrada en la tabla mount, entonces son el mismo fichero y se realiza la sustitución correspondiente en la tabla. Así es como está implementado el espacio de nombres.

Caché de ficheros

El protocolo 9P no tiene soporte explícito para cachear ficheros en un cliente. La extensa memoria del servidor central de ficheros actua como un caché compartido para todos sus clientes, lo que reduce la cantidad total de memoria necesaria para todas las máquinas de la red. No obstante, hay razones de peso para cachear ficheros en el cliente, como una conexión lenta con el servidor.

El campo version del qid se cambia siempre que el fichero se modifica, lo que posibilita en cierta forma el cacheo. Lo más importante es el cacheo en el cliente de los segmentos de texto y de datos de los ficheros ejecutables. Cuando un proceso ejecuta un programa, el fichero es reabierto y la versión del qid se compara con la del caché; si coinciden, se usa la copia local. El mismo método puede usarse para crear un servidor de ficheros local con caché. Este servidor de nivel usuario puede se interpone en la conexión 9P al servidor remoto y monitorea el tráfico, copiando datos al disco local. Cuando ve una lectura de datos conocidos, contesta directamente, mientras que las escrituras las pasa inmediatamente — el caché es escribible — para mantener los datos centrales actualizados. Esto es transparente para los procesos del terminal, y no requiere cambios en 9P; funciona bien en máquinas de casa conectadas por lineas serie. Un método similar puede aplicarse para construir un caché general de cliente en memoria local no utilizada, pero esto no se ha hecho en Plan 9.

Redes y dispositivos de comunicación

Los interfaces de red son sistemas de ficheros residentes del nucleo, análogos a los dispositivos EIA descritos anteriormente. Las llamadas de setup y shutdown pueden realizarse escribiendo cadenas de texto en el fichero de control asociado con el dispositivo; la información es enviada y recibida leyendo y escribiendo en un fichero de datos. La estructura y semántica del los dispositivos es común a todas las redes, así que aparte de cambiar el nombre del fichero, un mismo procedimiento puede llamar usando TCP sobre Ethernet como URP sobre Datakit [Fra80].

Este ejemplo ilustra la estructura de los dispositivos TCP:

Una llamada se inicia escribiendo un mensaje connect con una dirección de red como argumento; por ejemplo, para abrir una sesión Telnet (puerto 23) en una máquina remota con la dirección IP 135.104.9.52, la cadena es:

Una simple función de librería llamada dial se comunica con cs para establecer la conexión. Una aplicación que usa dial no necesita cambios, ni siquiera recompilación, para adaptarse a nuevas redes; el interfaz con cs oculta los detalles.

La uniforme estructura para las redes en Plan 9 hace que el comando import sea lo único que se necesita para construir una pasarela.

Estructura del nucleo para redes

La fontanería utilizada en el nucleo de Plan 9 para canales de comunicación se llama streams [Rit84][Presotto]. ??????????? Una stream es un canal bidireccional que conecta un dispositivo (físico o lógico) con un proceso de usuario. A stream is a bidirectional channel connecting a physical or pseudo-device to a user process. ??????????? El proceso de usuario inserta y retira datos en cada extremo de la stream; un proceso de nucleo, que actua en nombre del dispositivo opera al otro lado. Una stream comprende una lista lineal de módulos en proceso.

???????????? Cada módulo tiene una put routine. de upstream (hacia el proceso) y de downstream (hacia el dispositivo)

Each module has both an upstream (toward the process) and downstream (toward the device) put routine.

Una llamada a la rutina put del módulo en cualquiera de ambos lados inserta datos en la stream. Cada módulo llama sucesivamente a una para enviar datos desde o hacia la stream.

Calling the put routine of the module on either end of the stream inserts data into the stream. Each module calls the succeeding one to send data up or down the stream. ???????????

Al igual que en las streams de UNIX [Rit84], las de Plan 9 pueden configurarse dinámicamente.

El protocolo IL

El protocolo 9P debe ejecutarse sobre un protocolo de transporte fiable, con mensajes delimitados. 9P carece de mecanismos para recuperarse de errores de transmisión y el sistema sume que cada lectura de un canal de comunicación devolverá un solo mensaje 9P; no analiza la corriente de datos para descubrir límites de mensajes. Los pipes y algunos protocolos de red ya tienen estas propiedades, pero los protocolos estandar IP no. TCP no delimita los mensajes, mientras que UDP [RFC768] no proporciona una distribución en orden fiable.

Nosotros diseñamos un procoloco nuevo, llamado IL (Internet Link), para transmitir mensajes 9P sobre IP. Es un protocolo basado en conexión, que proporciona transmisiones fiables de mensajes en secuencia entre máquinas. Puesto que un proceso puede tener pendiente solamente una solicitud 9P, no hay necesidad de control de flujo en IL. Como TCP, IL tiene timeouts adaptables: escala los tiempos de acknowledge y retransmisión según la velocidad de la red. Esto le permite un buen rendimiento tanto en Internet como en Ethernet local. También, IL no hace retransmisión a ciegas, para evitar congestionar redes sobrecargadas. Todos los detalles sobre él están en otro documento [PrWi95].

En Plan 9, la implementación de IL es más pequeña y rápida que TCP. IL es nuestro protocolo de transporte principal de Internet.

Visión general de la autenticación

La autenticación establece la identidad de un usuario que accede a un recurso. El usuario que solicita el recurso se llama cliente y el usuario que garantiza acceso al recurso se llama servidor. Esto se hace usualmente bajo los auspicios de un mensaje 9P enganchado. El usuario puede ser cliente en un intercambio de autenticación y servidor en otro. Los servidores siempre actuan en nombre de un usuario, sea un cliente normal o una entidad administrativa, de modo que la autenticación se define entre usuarios, no entre máquinas.

Cada usuario de Plan 9 tiene una clave DES [NBS77] asociada; su identidad es verificada por la habilidad de desencriptar mensajes especiales llamados desafíos. Puesto que el conocimiento de la clave de un usuario da acceso a sus recursos, los protocolos de autenticación de Plan 9 nunca transmiten un mensaje que contenga la clave en texto plano.

La autenticación es bilateral: a cada extremo de un intercambio de autenticación, cada parte debe convencer a la otra de su identidad. Cada máquina empieza el intercambio con una clave DES en memoria. In el caso de servidores de CPU o de ficheros, la clave, nombre de usuario y de dominio para el servidor se leen del almacenamiento permanente, usualmente RAM no volatil. En el caso de terminales, la clave se deriva de la password tecleada por el usuario en el arranque. Una máquina especial, conocida como servidorde autenticación, mantiene una base de datos de claves de todos los usuarios en su dominio administrativo y participa en los protocolos de autenticación.

El procoloco de autenticación funciona así: después de intercambiar los desafíos, cada parte contacta con el servidor de autenticación para crear tickets de concesión de permisos encriptados con su clave secreta y que contienen una clave de conversación. Cada parte desencripta su propio ticket y usa la clave de conversación para encriptar el desafío de la otra.

Esta estructura es parecida a la de Kerberos [MBSS87], pero evita su dependencia de los bloques sincronizados. También, a diferencia de Kerberos, la autenticación de Plan 9 soporta la relación ‘hablar en nombre de’ [LABW91] que permite a un usuario tener la autoridad de otro; así es como un servidor de CPU realiza procesos en nombre de sus clientes.

La estructura de autenticación de Plan 9 construye servicios seguros, en lugar de depender de cortafuegos. Mientras que los cortafuegos requieren código especial para cada servicio que penetra el muro, el enfoque de Plan 9 permite que la autenticación se haga en un solo sitio — para todos los servicios — Por ejemplo, el comando cpu funciona con seguridad a través de Internet.

La autenticación de conexiones externas

El protocolo de autenticación normal de Plan 9 no es válido para servicios basados en texto como Telnet o FTP. En estos casos, los usuarios de Plan 9 se autentican con calculadores DES llamados autenticadores. El autenticador mantiene una clave para el usuario, distinta de su clave normal de usuario. El usuario entra en el autenticador con un PIN de 4 dígitos. Un PIN correcto habilita al autenticador para un intercambio desafío/respuesta con el servidor. Dado que dicho intercambio es válido solo una vez y que las claves nunca se envían por la red, este procedimiento no es susceptible a ataques de repetición, pero es compatible con protocolos como Telnet y FTP.

Usuarios especiales

Plan 9 no tiene super-usuario. Cada servidor es responsable de mantener su propia seguridad, normalmente permitiendo acceso solamente por la consola, que está protegida por una password. Por ejemplo, los servidores de ficheros tienen un único usuario administrativo llamado adm, con privilegios especiales que se aplican solamente a los comandos tecleados en la consola física del servidor. Estos privilegios conciernen al mantenimiento diario del servidor, como agregar usuarios y configurar discos y redes. Los privilegios no incluyen la capacidad de modificar, examinar o cambiar los permisos de ningún fichero. Si un fichero está protegido para lectura por el usuario, solamente él puede conceder a los demás acceso al mismo.

Los servidores de CPU tienen un nombre de usuario equivalente que permite el acceso administrativo a los recursos en ese servidor como los ficheros de control o los procesos de usuario. Este permiso es necesario, por ejemplo, para matar un proceso no deseado, pero no se extiende más alla de ese servidor. Por otra parte, por medio de la clave guardada en RAM no volatil, la identidad de un usuario administrador es probada para el servidor de autenticación. Esto permite al servidor de CPU autenticar a usuarios remotos, tanto para que accedan al servidor mismo como cuando el servidor está actuando como un proxy en nombre de ellos.

Finalmente, un usuario especial llamado none no tiene password y siempre se le permite conectarse; cualquiera puede ser none. None tiene permisos restringidos; por ejemplo, no se le permite examinar ficheros de volcado y solo puede leer los ficheros que son legibles para todo el mundo.

La idea de none es análoga al usuario anonymous de los servicios FTP. En Plan 9 además, los servidores FTP invitados son confinados dentro de un espacio de nombres especial restringido. Esto desconecta a los usuarios invitados de los programas del sistema, como los contenidos de /bin, pero posibilita el poner ficheros locales disponibles para ellos, enlazándolos explicitamente en el espacio. Un espacio de nombres restringido es más seguro que la técnica usual de exportar un arbol de directorios ad hoc; el resultado es una especie de jaula alrededor de los usuarios no fiables.

El comando CPU y la autenticación con proxy

Cuando se hace una llamada a un servidor CPU para un usuario, pongamos Peter, la idea es que Peter pueda ejecutar procesos con su propia autoridad. Para implementar esta propiedad, el servidor de CPU hace lo siguiente cuando se recibe la llamada. Este proceso cambia al usuario none para evitar regalar permisos si es comprometido. Luego realiza el protocolo de autenticación para verificar que el usuario que llama es realmente Peter, y para probar a Peter que la máquina también es de fiar. Finalmente, reengancha con todos los servidores de ficheros relevantes usando el protocolo de autenticación para identificarse a sí mismo como Peter. En este caso, el servidor de CPU es un cliente del servidor de ficheros, y realiza la parte del intercambio de autenticación del cliente en nombre de Peter. El servidor de autenticación le dará al proceso tickets para realizar esto solamente si al usuario administrativo del servidor de CPU se le permite hablar en nombre de Peter.

La relación habla en nombre de [LABW91] se mantiene en una tabla en el servidor de autenticación. Para simplificar la gestión de usuarios trabajando en distintos usuarios de autenticación, tambien contiene los mapeos entre nombres de usuarios en diferentes dominios, por ejemplo, si el usuario rtm en un dominio es la misma persona que el usuario rtmorris en otro.

Permisos de fichero

Una de las ventajas de la construcción de servicios como sistemas de ficheros es que la solución a los problemas de posesión y permisos viene dada naturalmente. Igual que en UNIX, cada fichero o directorio tiene permisos separados de lectura, escritura y búsquda/ejecución para el dueño del fichero, el grupo del fichero o para el resto. La idea de grupo es inusual: cualquier nombre de usuario es un nombre de grupo en potencia. Un grupo es solo un usuario con una lista de otros usuarios en su grupo. La diferencia es convencional: la mayor parte de la gente tiene nombres de usuario sin miembros en el grupo, mientras que los grupos tienen largas listas de nombres de usuario. Por ejemplo, el grupo sys agrupa tradicionalmenta a todos los programadores del sistema, y los ficheros del sistema son accesibles por el grupo sys. Considérese la siguiente base de datos de usuarios almacenada en un servidor:

Los ficheros regulares son poseidos por el usuario que los crea. El nombre del grupo se hereda del directorio que guarda el nuevo fichero. Los dispositivos se tratan especialmente: el nucleo puede arreglar la posesión y los permisos del fichero para adecuarlos al usuario que está accediendo al mismo.

Un buen ejemplo de la generalización que esto ofrece son los ficheros de proceso, los cuales son poseidos y protegidos para lectura por el dueño del proceso. Si el dueño quiere dejar a alguien acceso a la memoria del proceso, por ejemplo para dejar que el autor de un programa realice el debugging de una imagen rota, basta con aplicar el comando estandar chmod a los ficheros del proceso.

Otra aplicación habitual de los permisos de ficheros es el sistema de volcados, que no solamente es servido por el mismo servidor de ficheros que los datos originales, sino que también es representado por la misma base de datos de usuarios. Los ficheros del volcado siguien teniendo pués idéntica protección a los ficheros del sistema normal; si un fichero pertenece a pjw y está protegido para lectura, una vez que está en el volcado sigue perteneciendo a pjw y protegido para lectura. Además, puesto que el sistema de volcados es inmutable, el fichero no puede ser cambiado, y permanecerá para siempre protegido para lectura. Los inconvenientes son que si el fichero es legible pero debería haber estado protegido, permanecerá legible para siempre, y que los nombres de usuario son difíciles de reutilizar.

Rendimiento

Como simple medida del rendimiento del nucleo de Plan 9, hemos comparado el tiempo que se tarda en hacer algunas operaciones simples con él en un IRIX Release 5.3 de SGI, corriendo en una SGI Challenge M con un MIPS R4400 a 100 MHz con 1 megabyte de caché secundaria. El programa de test fué escrito en Alef, compilado con el mismo compilador, y ejecutado hardware idéntico, de modo que las únicas variables son el sistema operativo y las librerías.

El programa mide el tiempo que se tarda en hacer un cambio de contexto (rendezvous en Plan 9, blockproc en IRIX); una llamada al sistema trivial (rfork(0) y nap(0)); y una bifurcación ligera (rfork(RFPROC) y sproc(PR_SFDS|PR_SADDR)). También mide el tiempo de enviar un byte por un pipe desde un proceso a otro y el ????? throughput ?????? en un pipe entre dos procesos. El resultado aparece en la Tabla 1.

Tabla 1. Comparación de rendimiento.

Aunque los tiempos de Plan 9 no son espectaculares, demuestran que el nucleo es competitivo con sistemas comerciales.

Discusión

Plan 9 tiene un nucleo relativamente convencional, la novedad del sistema radica en las piezas que lo rodean y en la forma como interactúan. Cuando construimos Plan 9 consideramos todos los aspectos del sistema al mismo tiempo, resolviendo cada problema donde la solución encajaba mejor. A veces una solución abarcaba varios componentes. Un ejemplo es el problema de la heterogeneidad de instrucciones entre arquitecturas,

???????? que se resolvió por medio de compiladores (??????? diferentes caractéres de código ????????, codigo objeto portable), which is addressed by the compilers (different code characters, portable object code), ????????

el entorno ($cputype y $objtype), el espacio de nombres (enlaces a /bin), y otros componentes. Algunas cuestiones podían resolverse en un solo lugar. El mejor ejemplo es 9P, que centraliza el nombrado, acceso y autenticación. 9P es realmente el corazón del sistema; sería justo decir que el nucleo de Plan 9 es primordialmente un multiplexador de 9P.

El enfoque de Plan 9 sobre los ficheros y los nombres es capital para su expresividad. Particularmente en la computación distribuida, la forma en que se nombran las cosas tiene profunda influencia en el sistema [Nee89]. La combinación de espacios de nombres locales y convenciones globales para interconectar recursos en red evita la dificultadd e mantener un espacio de nombre global uniforme, mientras que nombrar todo como ficheros hace al sistema fácil de entender incluso para principiantes. Considérese el sistema de volcados, cuyo uso es trivial cualquiera familiar con los sistemas jerárquicos de ficheros. A un nivel más profundo, construir todos los recursos sobre un simple y uniforme interfaz facilita la ????????? interoperabilidad ????????????? Un interfaz 9P exportado por un recurso, puede combinarse transparentemente con cualquier otra parte del sistema para crear aplicaciones inusuales; los detalles quedan ocultos. Esto puede sonar ‘orientado a objetos’ pero hay diferencias. Primero, 9P define un conjunto fijo de ‘métodos’; no es un protocolo extensible. Más importante, los ficheros están bien definidos y estudiados, y vienen ya con métodos familiares de acceso, nombrado, protección y trabajo en red. Los objetos, a pesar de su generalidad, no vienen ya con esos atributos definidos. Reduciendo ‘objeto’ a ’fichero’, Plan 9 consigue bastante tecnología gratuitamente.

Aún así, es posible llevar la idea de la computación basada en ficheros demasiado lejos. Convertir cada recurso del sistema en un sistema de ficheros es una metáfora, y se puede abusar de las metáforas. Un buen ejemplo de restricción es /proc, que es solamente la vista de un proceso, no su representación. Para ejecutar procesos, sigue siendo necesario llamar a fork y a exec en lugar de hacer algo como

¿Qué haremos de forma diferente la próxima vez? Algunos elementos de la implementación no son satisfactorios. El uso de streams para implementar interfaces de red en el nucleo permite que varios protocolos se conecten simultáneamente de forma dinámica, como enganchar el mismo driver de TTY a conexiones UCP, URP y IL, pero Plan 9 no hace uso de esta configurabilidad. (Ha sido explotado, sin embargo, en la investigación de sistemas UNIX, para la que las streams fueron inventadas.) Reemplazar las streams por colas estáticas de E/S hubiese simplificado el código y lo hubiese hecho más veloz.

Aunque el nucleo principal de Plan 9 es portable entre muchas máquinas, el servidor de ficheros está implementado por separado. Esto ha causado varios problemas: drivers que deben ser escritos dos veces, errores que han de corregirse dos veces, y una peor portabilidad del código del sistema de ficheros. La solución es facil: el nucleo del servidor de ficheros debe mantenerse como una variante del sistema operativo, sin procesos de usuario y con procesos especiales para implementar servicio de ficheros. Otra mejora al sistema de ficheros sería un cambio de la estructura interna. El jukebox WORM es la pieza de hardware menos fiable, pero debido a que guarda los metadatos del sistema de ficheros, deben estar presentes para servir ficheros. El sistema puede ser reestructurado de modo que el WORM sea un dispositivo de backup solamente, con el sistema de ficheros real residiendo en discos magnéticos. Esto no requeriría ningun cambio en el interfaz externo.

Aunque Plan 9 tiene espacios de nombre pro proceso, no tiene un mecanismo para dar la descripción del espacio de nombres de un proceso a otro, excepto por herencia. El comando cpu , por ejemplo, no puede en general reproducir el espacio de nombres del terminal; solo puede reinterpretar el perfil de login del usuario y hacer sustituciones para cosas como el nombre del directorio de binarios. Esto hace que se pierda cualquier modificación local hecha antes de ejecutar cpu. En su lugar, debe ser posible capturar el espacio de nombres de la terminal y transmitir su descripción a un proceso remoto.

Aparte de estos problemas, Plan 9 funciona bien. Ha madurado y se ha convertido en un sistema que soporta nuestra investigación, en lugar de ser el sujeto de la misma. El nuevo trabajo experimental incluye desarrollar interfaces para redes más rápidas, cacheo de ficheros en el nucleo del cliente, encapsulación y exportación de espacios de nombres, y la posibilidad de reestablecer el estado del cliente después de una caída del servidor. La atención está ahora puesta en usar el sistema para construir aplicaciones distribuidas.

Una razón del éxito de Plan 9 consiste en que nosotros lo usamos para nuestro trabajo diario, simplemente como una herramienta de investigación. El uso activo nos fuerza a encarar los problemas según surgen, y a adaptar el sistema para resolverlos. A través de este proceso, Plan 9 ha llegado a ser un entorno de programación confortable y productivo, así como un vehículo para investigación de sistemas futuros.

Referencias

[9man] Plan 9 Programmer’s Manual, Volume 1, AT&T Bell Laboratories, Murray Hill, NJ, 1995.

[ANSIC] American National Standard for Information Systems - Programming Language C, American National Standards Institute, Inc., New York, 1990.

[Duff90] Tom Duff, ‘‘Rc - A Shell for Plan 9 and UNIX systems’’, Proc. of the Summer 1990 UKUUG Conf., London, July, 1990, pp. 21-33, reprinted, in a different form, in this volume.

[Fra80] A.G. Fraser, ‘‘Datakit - A Modular Network for Synchronous and Asynchronous Traffic’’, Proc. Int. Conf. on Commun., June 1980, Boston, MA.

[FSSUTF] File System Safe UCS Transformation Format (FSS-UTF), X/Open Preliminary Specification, 1993. ISO designation is ISO/IEC JTC1/SC2/WG2 N 1036, dated 1994-08-01.

[ISO10646] ISO/IEC DIS 10646-1:1993 Information technology - Universal Multiple-Octet Coded Character Set (UCS) — Part 1: Architecture and Basic Multilingual Plane.

[Kill84] T.J. Killian, ‘‘Processes as Files’’, USENIX Summer 1984 Conf. Proc., June 1984, Salt Lake City, UT.

[LABW91] Butler Lampson, Martín Abadi, Michael Burrows, and Edward Wobber, ‘‘Authentication in Distributed Systems: Theory and Practice’’, Proc. 13th ACM Symp. on Op. Sys. Princ., Asilomar, 1991, pp. 165-182.

[MBSS87] S. P. Miller, B. C. Neumann, J. I. Schiller, and J. H. Saltzer, ‘‘Kerberos Authentication and Authorization System’’, Massachusetts Institute of Technology, 1987.

[NBS77] National Bureau of Standards (U.S.), Federal Information Processing Standard 46, National Technical Information Service, Springfield, VA, 1977.

[Nee89] R. Needham, ‘‘Names’’, in Distributed systems, S. Mullender, ed., Addison Wesley, 1989

[NeHe82] R.M. Needham and A.J. Herbert, The Cambridge Distributed Computing System, Addison-Wesley, London, 1982

[Neu92] B. Clifford Neuman, ‘‘The Prospero File System’’, USENIX File Systems Workshop Proc., Ann Arbor, 1992, pp. 13-28.

[OCDNW88] John Ousterhout, Andrew Cherenson, Fred Douglis, Mike Nelson, and Brent Welch, ‘‘The Sprite Network Operating System’’, IEEE Computer, 21(2), 23-38, Feb. 1988.

[Pike87] Rob Pike, ‘‘The Text Editor sam’’, Software - Practice and Experience, Nov 1987, 17(11), pp. 813-845; reprinted in this volume.

[Pike91] Rob Pike, ‘‘8½, the Plan 9 Window System’’, USENIX Summer Conf. Proc., Nashville, June, 1991, pp. 257-265, reprinted in this volume.

[Pike93] Rob Pike and Ken Thompson, ‘‘Hello World or ???????? ?????????’’, USENIX Winter Conf. Proc., San Diego, 1993, pp. 43-50, reprinted in this volume.

[Pike94] Rob Pike, ‘‘Acme: A User Interface for Programmers’’, USENIX Proc. of the Winter 1994 Conf., San Francisco, CA,

[Pike95] Rob Pike, ‘‘How to Use the Plan 9 C Compiler’’, Plan 9 Programmer’s Manual, Volume 2, AT&T Bell Laboratories, Murray Hill, NJ, 1995.

[POSIX] Information Technology—Portable Operating System Interface (POSIX) Part 1: System Application Program Interface (API) [C Language], IEEE, New York, 1990.

[PPTTW93] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, and Phil Winterbottom, ‘‘The Use of Name Spaces in Plan 9’’, Op. Sys. Rev., Vol. 27, No. 2, April 1993, pp. 72-76, reprinted in this volume.

[Presotto] Dave Presotto, ‘‘Multiprocessor Streams for Plan 9’’, UKUUG Summer 1990 Conf. Proc., July 1990, pp. 11-19.

[PrWi93] Dave Presotto and Phil Winterbottom, ‘‘The Organization of Networks in Plan 9’’, USENIX Proc. of the Winter 1993 Conf., San Diego, CA, pp. 43-50, reprinted in this volume.

[PrWi95] Dave Presotto and Phil Winterbottom, ‘‘The IL Protocol’’, Plan 9 Programmer’s Manual, Volume 2, AT&T Bell Laboratories, Murray Hill, NJ, 1995.

[RFC768] J. Postel, RFC768, User Datagram Protocol, DARPA Internet Program Protocol Specification, August 1980.

[RFC793] RFC793, Transmission Control Protocol, DARPA Internet Program Protocol Specification, September 1981.

[Rao91] Herman Chung-Hwa Rao, The Jade File System, (Ph. D. Dissertation), Dept. of Comp. Sci, University of Arizona, TR 91-18.

[Rit84] D.M. Ritchie, ‘‘A Stream Input-Output System’’, AT&T Bell Laboratories Technical Journal, 63(8), October, 1984.

[Tric95] Howard Trickey, ‘‘APE — The ANSI/POSIX Environment’’, Plan 9 Programmer’s Manual, Volume 2, AT&T Bell Laboratories, Murray Hill, NJ, 1995.

[Unicode] The Unicode Standard, Worldwide Character Encoding, Version 1.0, Volume 1, The Unicode Consortium, Addison Wesley, New York, 1991.

[UNIX85] UNIX Time-Sharing System Programmer’s Manual, Research Version, Eighth Edition, Volume 1. AT&T Bell Laboratories, Murray Hill, NJ, 1985.

[Welc94] Brent Welch, ‘‘A Comparison of Three Distributed File System Architectures: Vnode, Sprite, and Plan 9’’, Computing Systems, 7(2), pp. 175-199, Spring, 1994.

[Wint95] Phil Winterbottom, ‘‘Alef Language Reference Manual’’, Plan 9 Programmer’s Manual, Volume 2, AT&T Bell Laboratories, Murray Hill, NJ, 1995.