Содержание


Inferno и Plan 9

Часть 1.Обзор

Comments

Серия контента:

Этот контент является частью # из серии # статей: Inferno и Plan 9

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Inferno и Plan 9

Следите за выходом новых статей этой серии.

Вступление

Все знатоки UNIX знают имена Кена Томпсона (Ken Tompson), Роба Пайка (Rob Pike) и Дениса Ритчи (Dennis Ritchie). Знают об их вкладе в индустрию IT, знают, что именно они являются создателями операционной системы UNIX, языка программирования Си и именно им принадлежат идеи файлов-устройств, конвейерной обработки данных, командного интерпретатора, работающего вне ядра ОС. Но немногим известно, что еще в конце 1980-х эти люди начали самый грандиозный и масштабный проект по уничтожению UNIX и ее родного языка Си, что именно в это время они приступили к работе над операционной системой, призванной уничтожить UNIX и придти ей на смену.

Закат UNIX

Основная проблема UNIX, с точки зрения ее же авторов, заключалась в том, что в силу своей архитектуры ОС не могла прозрачно приспособиться к значительно изменившемуся со времен ее разработки IT-миру. Проще говоря, UNIX умирала от собственных проблем, а все попытки приспособить ее к современным условиям приводили к усложнению ОС, введению множества разрозненных, сложных API, новых прослоек, сетевых протоколов, форматов данных, что сделало когда-то простую, продуманную, элегантную ОС тяжелым, неповоротливым и сложным в сопровождении комком кода.

Вспомните, каким была UNIX в начале своего рождения. Простая ОС, созданная для работы на мейнфреймах, с совсем небольшим набором системных вызовов и уникальным способом предоставления доступа к оборудованию с помощью набора синтетических файлов. Ее устанавливали на большие мейнфреймы, а пользователи, пожелавшие получить вычислительные мощности, подключались к ОС с использованием терминалов. Это была эпоха настоящей UNIX, работавшей в тех условиях, для которых она была спроектирована.

Со временем текстовые терминалы были вытеснены терминалами с дисплеями, сначала растровыми, а затем и графическими, но код ОС, отвечавший за вывод на терминал, оставался неизменным. С рождением сети ARPANET и протоколов TCP/IP в BSD-редакцию UNIX был добавлен код сетевого стека, но вместо синтетических файлов (файлов-устройств) его привязали к системным вызовам, реализующим модель сокетов. С появлением графических дисплеев и предложенной Xerox модели оконной среды, в UNIX была добавлена оконная графическая система X Window, но опять же, вместо привязки ее API к синтетическим файлам был разработан специальный протокол. Также были созданы сетевая файловая система NFS и одноименный сетевой протокол, различные системы удаленного вызова процедур, Kerberos и многое другое. В конце концов, идея мейнфремов с разделением времени не получила развития, и UNIX портировали на персональные рабочие станции и процессоры семейства i386.

PC-архитектура, предложенная IBM, предполагала возможность установки дополнительных плат, расширяющих функциональность рабочей станции. Поначалу пользователи имели доступ к ограниченному количеству простых плат расширения, но впоследствии возросли как их количество и разнообразие, так и сложность. Все это привело к тому, что некогда простое монолитное ядро UNIX (а теперь уже BSD и Linux) было разбито на модули, каждый из которых реализовал слой совместимости с платой расширения (драйвер), а простые в обращении синтетические файлы устройств, служившие точкой доступа к этому оборудованию, превратились в сложные интерфейсы, поддерживающие не только запись и чтение, но и множество так называемых вызов ioctl, иногда со сложными и совершенно неясными именами.

Время сделало так, что когда-то простая операционная система, созданная для работы на мейнфреймах, управляемых с помощью текстовых терминалов, сегодня работает на обособленных домашних ПК и серверах, объединенных в общую сеть. Мы давно избавились от текстовых терминалов, но постоянно работаем с их эмуляторами, мы привыкли к учетной записи root, которая была необходима во времена мейнфремов, а сейчас создает только бреши в безопасности, мы используем графический интерфейс, который совсем не вписывается в идеологию UNIX и существует как бы независимо от нее, у нас есть множество самых разнообразных способов связи с другими ПК, ни один из которых не является стандартным, мы используем специальные протоколы для доступа и управления другими машинами, мы вынуждены использовать сложнейшие механизмы RPC для создания распределенных приложений, мы удивляемся количеству системных вызовов в ядре Linux, и даже идея файлов-устройств уже потеряла свою универсальность и простоту.

План номер 9

Очевидно, что UNIX уже не исправить, ее убивает собственная архитектура. Поэтому исследователи из Bell Labs решили начать с нуля и разработали новую, никак не связанную и несовместимую с UNIX, ОС с эксцентричным именем Plan 9.

Главная идея Plan 9 заключалась в том, чтобы довести концепцию "все есть файл" до логического триумфа и построить из синтетических файлов всю ОС (а если говорить конкретнее – представить все ресурсы операционной системы файлами). Причем сделать это так, чтобы к файлам имели доступ не только локальные приложения и пользователи, но и любой удаленный клиент. В результате появился файловый протокол 9P, посредством которого происходит доступ к любым файлам (как к локальным, так и к удаленным), файловые серверы, экспортирующие некие ресурсы ОС или конкретные приложения в виде файлов, и пространство имен, призванное объединить все доступные файлы в единое дерево, к которому приложение или пользователь могут обращаться для поиска файлов и работы с ними.

В отличие от UNIX, которая четко разделяет "обычные" файлы и файлы-устройства, Plan 9 вообще лишена этих понятий. Все без исключения файлы, независимо от того, хранятся ли они на диске или были созданы каким-то файловым сервером, подчиняются единым правилам и могут быть доступны другим машинам в сети. А если копнуть еще глубже, то выясняется, что здесь нет даже "обычных" файлов, хранящихся на диске, ведь они тоже экспортируются файловыми серверами, реализующими драйвер файловой системы.

Все есть файл

Чтобы понять идеологию Plan 9, представьте, что пространство имен – это файловая система UNIX (внешне оно так и выглядит), начинающаяся с корня, в которой размещены каталоги и файлы, хранящие приложения, библиотеки, пользовательские данные и т.д. К любому каталогу этой файловой системы можно подключить (с помощью команд mount и bind) другое файловое дерево, но экспортированное не драйвером файловой системы, как это сделано в UNIX, а особым образом написанной программой, называемой файловым сервером.

Файловый сервер может быть приложением пользовательского уровня или компонентом ядра. По самой своей сути это просто программа, обслуживающая запросы клиентов, пришедшие по протоколу 9P. Так как 9P является файловым протоколом, то программа должна поддерживать список экспортируемых ей файлов (по сути, точек входа в программу) и обслуживать любые запросы на открытие/закрытие, чтение/запись любого из этих файлов. После подключения файлового сервера к пространству имен все экспортируемые им файлы становятся доступны остальным приложениям, которые могут использовать стандартные системные вызовы ядра (вроде open, read, seek и др.) для вызова определенных функций файлового сервера.

Все это очень похоже на взаимодействие программы и библиотеки функций с тем исключением, что 9P делает это взаимодействие гораздо более гибким. Для демонстрации этой гибкости возьмем файловый сервер стека протоколов TCP/IP, который реализован в ядре и носит имя '#I'. Подключив его к каталогу /net и выполнив команду 'ls /net' мы увидим примерно следующее:

% bind -a #I /net
% ls /net
/net/dns
/net/ether
/net/il
/net/tcp
/net/udp

Чтобы подключиться к удаленной машине используя протокол TCP, мы должны открыть файл /net/tcp/clone. Затем в каталоге /net/tcp появится управляющий каталог соединения, в ctl-файл которого мы можем записать команду "connect IP-адрес", записать запрос в файл data, а затем, прочитав его, получить ответ. На языке командного интерпретатора Plan 9 все это выглядит так:

<>[3]/net/tcp/clone {
        dir=/net/tcp/^`{cat <[0=3]}
        echo connect 74.125.77.99!80 >$dir/ctl &&
        {
                echo 'GET /search?q=Plan9&btnI=I''m+Feeling+Lucky HTTP/1.1' &&
                echo 'connection: close' &&
                echo 'host: www.google.com' &&
                echo ''
        }>$dir/data
        cat $dir/data
}

На низком уровне вся работа с файлами каталога /net будет сведена к вызовам функций файлового сервера '#I', поэтому пока никакого преимущества, кроме наглядности и возможности создавать соединения прямо из командной строки, мы здесь не видим. Однако если вспомнить, что все обращения к файлам в Plan 9 происходят через протокол 9P, то открывается новая возможность. Если мы импортируем каталог /net с удаленной машины, то, по сути, получим NAT:

% import -a удаленная-машина /net

Все обращения к файлам каталога /net будут передаваться удаленной машине, поэтому за инициацию соединения будет отвечать она. И все это без единой строчки дополнительного кода.

Но это еще не все. Пространство имен, с помощью которого происходит доступ к любым файлам ОС, индивидуально для каждого процесса, но может быть унаследовано от процесса-родителя. Следовательно, мы можем управлять доступом выбранного приложения к сетевой функциональности, просто не подключая файловый сервер '#I' к его пространству имен. Мы можем пойти еще дальше и сделать так, чтобы приложение имело доступ только к указанным нами сетевым протоколам путем установки соответствующих прав на подкаталоги каталога /net. Изменяя пространство имен, мы можем управлять тем, будет ли каталог /net доступен удаленным машинам или нет.

А ведь в Plan 9 файловые серверы везде. Это не только TCP/IP-стек, но и любой драйвер, файловая система, оконный графический интерфейс, почтовый сервер и многое другое. Любой ресурс Plan 9 представлен файловым сервером, в то время как API ядра всего лишь представляет функции для создания потоков, работы с файлами и модификации пространства имен. И каждый файловый сервер подчиняется всем описанным выше правилам. Так, файловая система /proc, предоставляющая доступ к свойствам и ресурсам процессов, может быть использована для отладки процесса, при этом удаленная машина вправе подключить ее к своему пространству имен для осуществления удаленной отладки. Процесс может быть помещен в песочницу простой модификацией его пространства имен, а текст помещен в графическое окно с помощью команды cat.

Протокол 9P и пространства имен делают Plan 9 идеальной средой для организации распределенных систем. Любой ресурс ОС, будь то обычный файл, хранящийся на диске, сам диск, мышь, клавиатура, дисплей, графическое окно, любое устройство может быть доступно с удаленной машины. Для машины, работающей под управлением Plan 9, совершенно безразлично, где располагаются ее ресурсы: каталог /bin может физически находиться на одной машине, для хранения файлов использоваться другая, а графический интерфейс работать на третьей. Plan 9 позволяет создать большой, производительный и устойчивый к сбоям метакомпьютер из горстки низкопроизводительных рабочих станций.

Безопасность

Система безопасности Plan 9 также вытекает из ее распределенной сущности. В то время как локальный пользователь машины, способный войти в систему только с терминала, обладает полными и неограниченными полномочиями, все остальные пользователи, попытавшиеся получить доступ к ресурсам ОС с удаленной машины, обязаны аутентифицировать себя путем предъявления сертификата, подписанного сервером сертификации. После этого соединение будет установлено, а все передаваемые в его рамках сообщения зашифрованы.

Управляя пространством имен, владелец машины может ограничить доступ удаленных пользователей только указанным кругом файлов и каталогов, а следовательно, и набором предоставляемых ему ресурсов и служб. При этом авторизация пользователей фактически осуществляется с помощью управления правами доступа к файлам, а брандмауэр не нужен в принципе, потому что в сети Plan 9 все соединения происходят с использованием протокола 9P.

Программирование

Концепция "все есть файл" существенно упрощает операционную систему и позволяет сделать процесс программирования приложений более ясным и универсальным.

Plan 9 не делает различий между локальными и удаленными ресурсами, избавляя программиста от необходимости писать лишний код, ответственный за сетевую функциональность. Все, что должна делать его программа – писать и читать файлы и производить проверки возвращаемых значений. При этом в его распоряжении находится множество специальных библиотек, служащих обертками для файлового интерфейса многих файловых серверов.

Интерфейс программирования Plan 9 составляют небольшой набор системных вызовов ядра и большое количество различных файлов, экспортируемых файловыми серверами. С большинством этих файлов можно работать без всяких оберток, через прямой вызов функций, таких как open, close, read, write и seek. Это делает API простым и легким для запоминания и использования.

Файловый интерфейс можно использовать из любого языка программирования без необходимости писать дополнительный связующий код. Так, с помощью языка командного интерпретатора программист может создать функционально-эквивалентный аналог почти любого приложения, доступного в Plan 9. То же самое можно сказать относительно любого другого языка.

Особого внимания заслуживает и тот факт, что Plan 9 не делает различий между процессами и нитями. Системный вызов rfork, предназначенный для разветвления процесса, принимает аргумент, используя который программист может указать, какие из ресурсов родительского процесса могут быть разделены с потомком, скопированы или созданы заново. Он позволяет тонко управлять "весом" потомка, который может стать легковесной нитью, разделяющей большинство ресурсов с родителем, или полноценным процессом, набор ресурсов которого обособлен. Системный вызов rendezvous обеспечивает синхронизацию процессов, позволяя организовать коммуникационные каналы, различные виды блокировок и механизмы перевода в состояние ожидания и активизации.

Inferno

В 1995 году компания Lucent Technologies, новый владелец исследовательских лабораторий Bell Labs, перевела многих разработчиков Plan 9 в другую команду, которая занялась созданием операционной системы Inferno, построенной на базе Plan 9. Руководство компании не без оснований полагало, что Plan 9, способная прозрачно и легко работать на компьютерах, организованных в распределенную вычислительную сеть, отлично покажет себя на маломощных мобильных устройствах и терминалах, которые в то время были просто обязаны перекладывать львиную долю своих функций на другие машины, чтобы обеспечить оптимальную производительность и удобство использования.

В результате родилась Inferno, операционная система, вобравшая в себя все преимущества Plan 9 и обладающая рядом уникальных черт. В основе новой ОС лежало урезанное ядро Plan 9 с переработанной графической подсистемой, выше располагалась высокопроизводительная виртуальная машина Dis, предназначенная для исполнения переносимого процессорно-независимого байткода, а в качестве языка прикладного программирования использовался Limbo, высокоуровневый модульный язык со встроенной поддержкой многопоточного программирования. Кроме того, Inferno обладала способностью работать не только на многих процессорных архитектурах, но и быть приложением внутри существующих ОС, таких как Windows, Linux, Solaris, AIX и других.

Эти особенности делали Inferno идеальной площадкой для организации самых разных распределенных систем. Inferno работала в буквальном смысле на всем, позволяла переносить приложения между платформами не только без модификации, но и без перекомпиляции. Протокол 9P (переименованный в Styx) обеспечивал простой унифицированный способ доступа к ресурсам. Язык Limbo превращал разработку распараллеленных приложений в развлечение.

Виртуальная машина

Несмотря на использование виртуальной машины (ВМ), которая в теории должна была привести к резкому падению скорости исполнения приложений, операционная система показывает впечатляющую производительность. И тому есть простое объяснение: Inferno – коммерческий продукт, поэтому при проектировании Dis исследователи из Bell Labs пошли против принципов и сделали все, чтобы сделать ВМ более привлекательной, с коммерческой точки зрения, технологией. В результате Dis обзавелась следующими характеристиками:

  1. Dis – виртуальная машина типа "память-в-память". В отличие от Java VM и многих других стековых виртуальных машин, Dis обладает наиболее оптимальной для реализации JIT-архитектурой. Если в режиме интерпретации производительность Dis ниже стековых виртуальных машин, то ее JIT-компилятор с легкостью обгоняет своего аналога в стековых ВМ, а уровень потребления памяти остается минимальным. Архитектура "память-в-память" усложняет компилятор, но позволяет сделать JIT-компилятор гораздо более простым и быстрым.
  2. Набор инструкций виртуальной машины максимально приближен к набору инструкций современных процессоров. Это означает, что для интерпретации достаточно большого количества инструкций виртуальной машине необходимо выполнить всего 1–2 инструкции целевого процессора (вместо 10–20 в других ВМ).
  3. Dis реализует избыточный набор высокоуровневых инструкций (CISC-машина) вместо минимального и единственно необходимого (RISC-машина, к которой можно отнести большинство других ВМ). Наравне с такими низкоуровневыми инструкциями, как сложение, вычитание, умножение, сдвиг, переход и т.д., словарь Dis составляют инструкции для работы с каналами, списками, массивами, инструкции для порождения потоков, загрузки модулей и т.д. Все они способствуют ускорению исполнения приложений, написанных на Limbo, но никак не привязывают виртуальную машину к единственному языку.
  4. Dis использует гибридный сборщик мусора. Большая часть мусора собирается с помощью подсчета ссылок, в то время как помечающий сборщик собирает данные в режиме реального времени. В отличие от Java VM и других, набор инструкций Dis не создает сложностей в отслеживании ссылок на копируемые объекты, а значит, память может быть освобождена без промедлений и вызов помечающего сборщика отложен.
  5. Наиболее требовательные к ресурсам компоненты операционной системы Inferno реализованы на языке Си. Inferno насчитывает семь встроенных модулей, включая sys (системные вызовы и часто используемые функции), draw (работа с видеоадаптером и графическими примитивами), Tk (библиотека графических виджетов, на которых строится интерфейс большинства приложений), freetype (растеризатор шрифтов) и keyring (алгоритмы шифрования, работа с сертификатами и т.д.). Каждый из них реализован на языке Си и потому исполняется с почти максимально возможной скоростью.

Limbo

Кроме переносимости и производительности, Inferno обладает еще одной очень важной особенностью: наличием языка прикладного программирования Limbo, который был разработан с нуля специально для Inferno и существует только в рамках этой ОС. Его синтаксис во многом повторяет синтаксис Си, но имеет вкрапления из множества других языков. Характеристики этого языка несколько необычны, но более чем разумны.

  1. Строгая типизация. Limbo – язык со строгой типизацией, а это значит, что в нем нет указателей, подобных Си (есть ссылки, но в них нельзя записать произвольный адрес), нет неявного преобразования типов (в то время как явное всегда дает ожидаемый результат). Проверка типов осуществляется как на этапе компиляции, так и во время исполнения. Все это способствует повышению безопасности и более ожидаемому поведению приложений, а также позволяет отказаться от использования блока MMU-процессора для изоляции данных процессов/потоков и таким образом повысить производительность ОС (Inferno в принципе не позволяет исполнять сторонний код ниже виртуальной машины).
  2. Модули. Limbo – модульный язык, что вкупе со стилем объявления/инициализации переменных делает его похожим на язык Modula. Начав изучать Inferno, вы заметите, что в ней нет понятия исполняемых файлов и библиотек. Весь скомпилированный Dis-байткод хранится в модулях, каждый из которых может быть как запущен из командной строки, так и использован другим модулем в качестве библиотеки функций. При этом код модуля исполняется в отдельном потоке, не дублируется в памяти и может быть загружен многократно. Если вы работали с операционными системами Oberon и AOS, то поймете, о чем я говорю.
  3. Поддержка параллельного программирования. Limbo ведет свою историю от Newsqueak, предком которого был Squeak, экспериментальный язык Роба Пайка, предназначенный для параллельного программирования. Язык поощряет создание многонитевых приложений, всячески этому содействуя. Так, в Limbo (и, соответственно, Dis) встроена поддержка двунаправленных каналов (буферизированных и небуферизированных), оператор создания нового потока spawn и оператор выбора канала alt, по своему назначению сходный с системными вызовами epoll в Linux, kqueue во FreeBSD и /dev/poll в Solaris.
  4. Высокоуровневые конструкции. Limbo поддерживает такие типы данных, как строки, списки, кортежи и абстрактные типы данных (нечто вроде структур, которые могут инкапсулировать не только данные, но и функции), а также специальные конструкции для работы с ними. Так, строки разрешается складывать, сравнивать, обрезать, преобразовывать в массивы, списки можно обрабатывать с помощью конструкций языка для получения их головы и хвоста, кортежи можно преобразовывать в массивы и т.д.

Следующий код, размещенный на сайте Vita Nuova (текущий владелец Inferno, http://www.vitanuova.com), демонстрирует то, как в Limbo происходит работа с потоками и каналами:

implement Timer2;

include "sys.m";
	sys: Sys;
include "draw.m";

Timer2: module {
	init: fn (nil: ref Draw->Context, argv: list of string);
};

init(nil: ref Draw->Context, argv: list of string)
{
	sys = load Sys Sys->PATH;

	sync := chan of int;
	n := len argv;
	spawn timer(sync, n);

	sys->print("Command Line Parameters\n");
	for (i := 0; i < n; i++) {
		<-sync;
		sys->print("%d: %s\n", i, hd argv);
		argv = tl argv;
	}
}

timer(sync: chan of int, n: int)
{
	for (i := 0; i < n; i++) {
		sys->sleep(1000);
		sync <-= 1;
	}
}

Исполнение приложения начинается с функции init(). Строка "sync := chan of int;" создает канал для передачи сообщений типа int. С помощью оператора spawn порождается новый поток, исполняющий функцию timer, которая каждую секунду посылает в канал сообщение "1". При этом родительский процесс входит в цикл, который блокируется до появления сообщения в канале (<-sync;), а после этого печатает аргумент командной строки. Количество проходов цикла равно количеству аргументов командной строки, а результатом программы будет печать всех аргументов с интервалом в одну секунду.

Совместимость

Имея виртуальную машину и новый язык, Inferno совсем не теряет совместимости с уже существующими приложениями. Работая поверх другой ОС, Inferno позволяет вызывать другие приложения этой ОС, используя специальный интерфейс, поэтому в тех случаях, когда Inferno используется в качестве платформы для создания распределенных приложений, уже существующие приложения могут быть без каких-либо изменений запущены внутри Inferno-окружения. Интерфейс встроенных модулей позволяет встроить любой Си-код в ядро Inferno, создать интерфейс для доступа к этому коду из Limbo и таким образом расширить функциональность среды исполнения. В комплект входит реализация протокола 9P/Styx, написанная на языке Си для POSIX-совместимых платформ. Ее задача: связать Inferno с любыми внешними приложениями как внутри одной ОС, так и удаленно.

Заключение

Plan 9 очень гибкая, но требующая переосмысления принципов построения программных систем, операционная система. Сегодня она используется множеством энтузиастов по всему миру в качестве распределенной ОС. IBM использует Plan 9 и некоторые компоненты Inferno на одной из своих суперкомпьютерных систем Blue Gene/L, построенной на базе 64000 процессоров. Plan 9 использовалась для управления системой освещения стадиона на олимпийских играх в Сиднее в 2000 году. Это живая ОС, которая могла бы стать будущим, если бы ее ниша не была занята UNIX, которая, по словам Эрика Реймонда (Eric Steven Raymond), "скрипит, гремит и имеет очевидные пятна ржавчины, однако она выполняет свою работу достаточно хорошо для того, чтобы удерживать позиции".

В то же время Plan 9 оставила свой след и в UNIX. Системные вызовы rfork во FreeBSD и clone в Linux смоделированы по образу и подобию своего аналога из Plan 9, файловая система /proc в Linux и FreeBSD была заимствована из Plan 9, файловая система /sys в Linux точно следует модели файловых серверов Plan 9, предоставляя способ получения информации об оборудовании без использования вызовов ioctl. Кодировка UTF-8, сегодня используемая всюду, от ОС UNIX и до Web-приложений, была создана для использования в Plan 9.

Inferno, с другой стороны, могла бы стать отличной, производительной, продуманной и удобной для программистов платформой, способной "заткнуть за пояс" Java и C# вместе взятые. Она смогла бы потягаться с erlang и стала бы отличной ОС для встраиваемых устройств. Но всего этого не произошло благодаря скудной рекламе, завышенной цене, головотяпству компаний-владельцев и отвратительному, с точки зрения маркетинга, названию.

Inferno имеет множество преимуществ перед другими платформами, но для понимания ее философии, не говоря уже о переходе, требуется слишком резкое изменение угла зрения, для чего в большинстве случаев нет ни времени, ни средств. Если же вы хотите найти идеи Inferno в современном мире, то взгляните на Android, которая оснащена сходной с Dis виртуальной машиной, использует компоненты, написанные на языке Си для повышения производительности, и даже имеет механизм передачи сообщений для общения процессов.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=487252
ArticleTitle=Inferno и Plan 9: Часть 1.Обзор
publish-date=05042010