В начале 1997 г. компания Lucent Technologies выпустила первую версию своей новой "сетецентрической" операционной системы, получившей название Inferno.
В этой статье дается общая характеристика Inferno, описывается системы организация и исследуются возможные последствия ее появления для рынка сетевых компьютеров.
Пироз МосениПример простой программы на языке Limbo
Настанет день, и телефонные аппараты смогут принимать электронную почту, а телевизоры - показывать Internet-страницы. Появление подобных устройств не за горами, причем в развитии рынка сетевых устройств должна, по-видимому, сыграть важную роль концепция сетевого компьютера (Network Computer, NC).
Важным компонентом сетевых устройств является операционная система. Inferno - компактная ОС, предназначенная специально для работы в сети, - идеально подходит для рынка таких устройств. Она работает с рядом различных сетей и машин. Прикладные программы адекватно видят сеть, поскольку ОС учитывает все детали организации сети. Inferno разработана компанией Lucent Technologies, отделившейся от AT&T Technologies.
Три главных принципа Inferno
В основу Inferno положены три простых принципа. Все они связаны с сетью и "сетецентрической" моделью.
Первый состоит в том, что обращение ко всем ресурсам, доступным прикладной программе, осущесствляется на основе единого протокола. Этот протокол, получивший название Styx, обеспечивает взаимодействие и с локальными ресурсами, такими как локальные файлы и диски, и с удаленными, такими как файлы на других машинах и серверы баз данных.
Второй принцип - это представление всех ресурсов в виде файлов в иерархической файловой системе (так же, как в Unix). Операции открытия, чтения, записи и закрытия применяются к принтерам, базам данных, сетевым соединениям, удаленным файлам. То, что все ресурсы рассматриваются как файлы, значительно упрощает организацию сети с точки зрения прикладной программы.
Третий принцип, на котором основана Inferno, заключается в том, что прикладные программы работают с сетью и только с сетью. Элементы файловой системы могут представлять собой смесь локальных и удаленных ресурсов, но для прикладных программ это не имеет значения. Обращения к ресурсам, разбросанным по разным машинам сети, ничем не отличаются для них от обращений к локальным ресурсам своей собственной машины.
Таким образом, вид вычислительной среды из программ Inferno оказывается более "сетецентрическим", чем из Java-программ: в Java обращение к удаленному и к локальному файлу осуществляется различным образом. В Inferno сделана попытка ликвидировать это различие. Не будем забывать, что Inferno представляет собой ОС, предназначенную в первую очередь для сетевых устройств. Язык Java лишь совсем недавно стал проникать на этот рынок вместе с Java OS.
Основные компоненты Inferno
Система Inferno имеет полный набор компонентов, необходимых для ее установки непосредственно на компьютер (вероятно, это и будут делать производители сетевых устройств). Такой вариант называется установкой в естественной среде (native environment).
Можно установить Inferno и поверх уже имеющейся на машине ОС, например Unix или Windows NT, осуществив так называемую установку в искусственной среде (emulation environment). Эта статья относится в основном к функционированию Inferno в искусственной среде - поверх Windows NT 4.0. Экземпляр Inferno можно получить по адресу http://inferno.lucent.com/inferno.
ОС Inferno состоит из четырех отдельных частей*:
- Операционная система Inferno (ядро).
- Язык программирования Limbo.
- Виртуальная машина Dis.
- Протокол связи Styx.
Язык программирования Limbo и виртуальная машина Dis очень схожи соответственно с Java и Java-машиной. Limbo - это язык, синтаксически близкий к Си (а не к Си++, как Java); он предназначен для написания прикладных программ, работающих под управлением Inferno. Компилятор Limbo генерирует не зависящий от системы байтовый код, который может исполняться на любой виртуальной Dis-машине. Таким образом, программы, написанные на Limbo, будут выполняться на любой машине, поддерживающей Inferno. В настоящее время Limbo - единственный язык программирования для Inferno.
Сердце системы - это ее ядро (собственно Inferno) и протокол Styx. Ядро отвечает за низкоуровневые задания, такие как распределение ресурсов, защиту и взаимодействие с аппаратурой. Сетевые операции обеспечиваются протоколом Styx, который, в свою очередь, подчинен ядру. В силу очевидных причин определенные части ядра зависят от аппаратуры, так что для разных машин и конфигураций необходимы разные ядра. Код ядра написан на стандартном Си (ANSI C), так что его относительно просто перенести в любую вычислительную среду, для которой существует компилятор языка Си. Согласно документации, ядро Inferno уже перенесено на аппаратные архитектуры MIPS, SPARC, Intel 386, 486 и Pentium, а также AMD 29000 и ARM.
В следующих разделах мы подробнее остановимся на каждой из четырех составных частей Inferno.
Ядро Inferno: основа ОС
Ядро - нижний уровень программного обеспечения Inferno, поддерживающий функционирование уровней сети и прикладных программ. Ядро отвечает за управление процессами, памятью, вводом-выводом и пространством имен (name space).
Память организована в виде несбалансированного B-дерева, листы которого рассортированы по размеру. Когда процесс запрашивает память, система просматривает B-дерево и находит в нем блок, удовлетворяющий запросу. Если размер блока более чем на 25% превышает требуемый, он разбивается на две части, одна из которых отдается процессу, а другая присоединяется обратно к B-дереву. Если разница в размере меньше 25%, блок отдается процессу целиком и оставшееся пространство не используется.
Другая задача, которую естественно решать ядру ОС, - это распределение времени между процессами. В Inferno различаются восемь классов (приоритетов) процессов, причем каждому соответствует отдельная очередь. Inferno выделяет время фиксированными порциями и обслуживает все восемь очередей по круговой схеме.
Все устройства, как и в Unix, включены в файловую систему. Символ "/" обозначает корневую файловую систему. Имена остальных устройств представляют собой последовательности из символа "#" ("решетки") и некоторой буквы. Например, #V означает телевизионные устройства, а #D - уровень защиты гнезд. Связь с устройствами осуществляется по сети.
Важной функцией ядра операционной системы является создание и поддержка пространств имен. Пространство имен обеспечивает процессу видение ресурсов. Для включения в файловую систему монтируют (mount), а затем подключают (bind) к пространству имен.
Локальные ресурсы, такие как локальные файлы, обычно монтируются при инициализации системы. Например, если в момент запуска включена видеокамера, автоматически монтируется локальное видеоустройство. Для обращения к удаленным ресурсам программа должна смонтировать их в явном виде; в языке Limbo для этого имеется специальная конструкция. Затем смонтированный ресурс подключается к нужному пространству имен. Например, можно смонтировать удаленную файловую систему и подключить ее к локальной файловой системе. После этого удаленная файловая система будет рассматриваться программой как часть локальной.
Перед тем как соединение между двумя системами будет установлено, оно должно пройти проверку на соответствие требованиям защиты, осуществляемую ядром ОС. В сетевом окружении чрезвычайно важно ограничивать ресурсы, к которым предоставляется доступ. Так, возможность посмотреть любимый фильм по интерактивному телевидению вы получите лишь после того, как соответствующее устройство будет опознано как зарегистрированное видеосервером компании кабельного телевидения. Для опознавания систем используется шифрование с открытым и закрытым ключами. Помимо этой первичной проверки защита осуществляется на уровне прикладных программ. Для одних программ дополнительная защита может оказаться необходимой, для других - излишней.
Модель защиты в Inferno более изощренная, чем в Java, однако она появилась совсем недавно и, как следствие, изучена менее тщательно.
Протокол Styx: взаимодействие с сетью
Протокол связи Styx используется устройствами Inferno для взаимодействия с сетью и совместного использования сетевых ресурсов. Сетевые соединения, естественно, представлены как часть файловой системы. Файловая система сервера обычно содержит представления тех сетевых служб, которые обеспечиваются данным сервером, а также тех, которые ему доступны. Чтобы клиент мог получить доступ к ресурсам, на нем должно быть создано то же их представление, что на сервере. Это осуществляется путем монтирования и подключения, как было описано выше. Проверка соответствия запроса на монтирование требованиям защиты возлагается на сервер. Сервер также отвечает за предоставление различным клиентам одного и того же ресурса и несовпадение точек монтирования. При иерархической системе данная задача решается в значительной мере "в лоб", поскольку каждый клиент располагает на сервере собственным пространством.
В Styx различаются два типа сообщений: передача начала протокола (T-сообщение) и передача ответа (R-сообщение). Указание на тип содержится в первом байте сообщения. Следующие два байта представляют собой метку (tag), устанавливаемую клиентом и служащую для идентификации сообщения. Каждое исходящее от клиента сообщение (за исключением абсолютно тривиальных) должно иметь уникальную метку, позволяющую его однозначно идентифицировать. Четвертый и пятый байты - это идентификатор файла, над которым производится операция; они имеют смысл только в том случае, когда сообщение относится к файлу. Оставшаяся часть сообщения содержит данные, определяемые выполняемой операцией.
Структура сообщения показана на рисунке.
По своему назначению сообщения Styx подразделяются на четыре категории:
Как уже говорилось, детали функционирования протокола Styx на уровне прикладных программ оказываются скрыты; это сильная сторона Inferno. Запрос на монтирование может транслироваться во множество различных сообщений Styx, но это происходит "за сценой". Прикладному программисту нужно лишь смонтировать конкретный сетевой ресурс, с которым должна работать программа. Inferno и Styx это обеспечивают.
В Java нет уровня, в точности соответствующего Styx. Для доступа к сетевым ресурсам там используются техника сокетов, RMI (Remote Method Invocation - активизация удаленного метода) и связь по протоколу HTTP. Все эти механизмы поддерживаются языком и виртуальной машиной, однако поддержка сетевых функций и сообщений в Inferno осуществляется более естественно.
Виртуальная машина Dis
При чтении разделов, посвященных Dis и Limbo, вам наверняка бросится в глаза их сходство с JVM и Java. Программы на Limbo интерпретируются виртуальной машиной Dis. Она отвечает за распределение памяти и времени, а также за "сборку мусора". На компьютере всегда работает только один экземпляр Dis, на который бывает возложено управление кучей: он извлекает из кучи и выдает программе необходимую ей память.
При управлении памятью Dis опирается на описатели типа (type descriptors). Каждому объекту, занимающему память, приписан описатель типа, содержащий размер объекта и указатели на другие объекты в куче. Соответствующая информация генерируется компилятором Limbo и используется Dis-машиной для обеспечения защиты памяти.
Нити управления помещаются в очередь и выполняются по круговой схеме. Закончив работу, нить покидает очередь и возвращает использовавшиеся ею ресурсы Dis-машине. Нить, не способная выполнить свои задачи в отведенное ей время, удаляется из очереди и помещается в специальную очередь, ожидающую ресурсов центрального процессора.
Нити, взаимодействующие с другими нитями, могут, кроме того, приостанавливать работу. Если нить переведена в состояние send (посылка сообщения), она останется в этом состоянии до тех пор, пока нить-адресат не подтвердит, что сообщение получено. Аналогично ведут себя нити и при входе в состояние receive (получение сообщения). Благодаря тому что нити остаются в состоянии отправки и получения сообщения до завершения связи, Dis расширяет возможности сетевых коммуникаций и исключает преждевременное разъединение, сокращая тем самым общее число соединений и нитей.
И наконец, в определенных случаях ресурс бывает нужен ядру. Тогда оно блокирует нить, использующую этот ресурс, на время выполнения жизненно важных системных функций.
В Dis используется два типа механизмов "сборки мусора". Первый - это счет ссылок (reference counting), при котором использованная память становится доступной сразу после освобождения. Второй - маркирование и очистка (mark-and-sweep). Он применяется только к циклическим структурам и выполняется как отдельный фоновый процесс.
Язык программирования Limbo
На Limbo пишутся программы для Inferno. Разрабатывая прикладные программы, вы будете иметь дело в первую очередь с этим языком и лишь во вторую - с Dis-машиной, протоколом Styx и ядром Inferno. Синтаксис Limbo очень похож на синтаксис Си (но не Си++). Язык поддерживает основные типы данных, циклы и структуры принятия решений, а также надежный коммуникационный интерфейс. Полное описание языка можно получить на Web-странице Inferno.
Программа на Limbo состоит из единиц, называемых модулями. Каждый модуль содержит интерфейсную декларативную секцию (declaration part) и секцию реализации (implementation part). В декларативной секции перечисляются функции и данные, предоставляемые модулем, а также типы данных и всевозможные константы. В секции реализации находятся реализации функций модуля и, если нужно, реализации вспомогательных внутренних функций.
Пример простой программы на Limbo приведен в листинге. Если ее запустить, она печатает сообщение This is my first Limbo program (это моя первая программа на Limbo). Первая строка указывает, что программа реализует модуль под названием FirstProgram. Следующие две представляют собой операторы включения, аналогичные оператору #include в Си. Оператор печати входит в модуль sys.m. Далее идет строка, определяющая переменную под названием sys, которая представляет собой экземпляр модуля Sys. Впоследствии эта переменная используется для обращения к функции печати.
Вслед за ней помещается декларативная секция программы, где объявляется модуль FirstProgram и его единственная функция. Имя функции - init, ее аргументы - контекст (ctxt) и список строк (argv).
За декларативной секцией следует секция реализации. Обратите внимание: имена функции и параметров повторяются; они всегда должны совпадать с именами в декларативной секции. Функция init (аналог функции main() в Си) первым делом вызывает функцию load, чтобы связать переменную sys с модулем Sys. Запись Sys->PATH относится к константе, объявленной в модуле Sys, которая содержит путь к нему. По имеющемуся соглашению такая константа присутствует во всех системных модулях Inferno.
Теперь, когда переменная sys стала экземпляром модуля Sys, ее можно использовать для вызова функции печати, применяя форму записи
sys->print(string);
где string - то сообщение, которое должно быть напечатано.
Поскольку Limbo основан не на Си++, а на Си, он не является объектно-ориентированным в том же смысле, что Java. На настоящий момент Limbo - единственный язык, поддерживаемый в Inferno; в дальнейшем планируется добавить также поддержку Java.
Кроме описания Limbo на Web-странице Inferno имеется хороший очерк языка, написанный Брайаном Керниганом (одним из авторов Unix и языка Си. - Прим. ред.). Он озаглавлен A Descent into Limbo (на русский язык это можно было бы перевести как "В круге первом". - Прим. перев.)
API
Подобно языку Java, к которому прилагаются стандартные пакеты, библиотеки классов и API, Limbo также имеет свой API. Его функции гарантированно будут работать во всех реализациях Inferno, так что ваша программа на Limbo, соответствующая API, будет работать во всем множестве реализаций системы. Файлы (модули) API обычно имеют расширение .m и хранятся в подкаталоге модулей. Они обеспечивают широкий спектр операций - от работы со строками и защиты до проектирования графических интерфейсов.
Пироз Мосени - консультант по программному обеспечению, специализирующийся в области технологий Web, баз данных и Java. Эта статья предтавляет собой отрывок из его книги Waite Group's Guide to NC, подготовленной к публикации издательством Waite Group Press (http://www.mcp.com/waite/waite/). Это же издательство ранее выпустило его книгу Web Database Primer Plus. E-mail: piroz.mohseni@ncworldmag.com
Пример простой программы на языке Limbo
implement FirstProgram include "sys.m" include "draw.m" sysSys; FirstProgrammodule { initfn (ctxtref Draw->Context, argvlist of string); }; init(ctxtref Draw->Context, argvlist of string) { sys=load Sys Sys->PATH; sys->print ("This is my first Limbo program. "); }
* Названия компонентов системы взяты из "Божественной комедии" Данте. Inferno - это Ад, Limbo - Лимб, первый, самый внешний круг Ада, где живут праведники-нехристиане и герои древности, Dis - Дит, название цитадели Ада и одно из имен владыки Ада Люцифера, Styx - Стикс, река, протекающая в Аду неподалеку от стен Дита.