Введение
Язык Определения Интерфейсов (IDL)
Объекты в Spring
Общая структура системы
Nucleus
Сетевые посредники
Модель безопасности Spring
Виртуальная память
Файловая система
Механизм именования Spring
Эмуляция ОС UNIX
Выводы
Литература

Spring - высоко модульная, обьектно-ориентированная операционная система. Статья описывает цели системы Spring и содержит обзор обьектной модели Spring, модели безопасности и именной архитектуры. Представлены детали реализации микроядра Spring, системы виртуальной памяти, файловой системы и эмуляции ОС UNIX.

Введение

Как бы Вы поступили, если бы перед Вами лежал чистый лист бумаги, предназначенный для проекта новой операционной системы? Сделали бы новую ОС в точности похожей на некоторую уже существующую или нет?

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

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

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

В чем главные проблемы существующих систем? С точки зрения компании Sun, которая в своих продуктах Solaris поставляет технологии, основанные на системе UNIX, они таковы:

- стоимость сопровождения, развития и поставки системы, включая как относящийся, так-н не относящийся к ядру код (например, оконные системы);
- базовые средства обеспечения безопасности, обычно не слишком гибкие, не слишком легкие в использовании и не слишком безопасные;
- трудность построения распределенных, многонитевых приложений и сервисов;
- трудность поддержки критичных ко времени приложений (аудио и видео), особенно в сетевой среде;
- недостаток унифицированного метода обнаружения-объектов по имени (по-разному устроен просмотр для файлов, устройств, пользователей и т. д.)..
С другой стороны, мы хотели сохранить ряд средств, доказавших свою практичность в одной или нескольких системах, в частности:
- хорошую производительность на широком спектре машин, включая многопроцессорные системы;
- защиту памяти, виртуальную память и отображаемые файловые системы;
- доступ к существующим системам благодаря совместимости приложений и сетевой интероперабельности (например, стандартные протоколы и сервисы);
- оконные системы и графические пользовательские интерфейсы.

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

Просмотрев этот список, мы немедленно решили, что система Spring нуждается в строгой и явной архитектуре. Другими словами, следует уделить внимание интерфейсам между программными компонентами, выражающими, в действительности, структуру системы. Затем было сформулировано требование к архитектуре Spring.

- Компоненты Spring должны определяться строгими интерфейсами, а сама система должна быть открытой, гибкой и расширяемой.

Под строгим мы понимаем такой интерфейс, который специфицирует, что делает некоторый программный компонент, очень мало при этом сообщая о том, как он реализован. Стремление достичь поставленной цели привело нас к развитию идеи Языка Определения Интерфейса (IDL - Interface Definition Language) [15], который дал бы нам возможность определять интерфейсы программного обеспечения, не ограничивая рамками какого-либо одного языка программирования, что сделало бы систему менее открытой. Мы уверены также, что лучший способ придать системе многие из перечисленных свойств состоит в использовании объектно-ориентированного подхода.

Тесный союз строгих интерфейсов и объектной ориентированности является естественным и весьма мощным. Он помогает достичь таких целей, как открытость, расширяемость, легкая организация распределенных вычислений и безопасность. В частности, такой подход позволяет добиться соответствия типов, безопасности (при необходимости) и унифицированности при вызове операций над объектом, вне зависимости от того, размещаются ли объект и обратившийся к нему клиент в одном адресном пространстве или на одной машине, либо удалены друг от друга.

Согласованно с IDL-интерфейсами мы использовали подход, основанный на микроядре. Spring Nucleus (часть микроядра) непосредственно поддерживает безопасные объекты с высокоскоростным обращением к объектам между адресными пространствами (и, в рамках расширения системы, между соединенными сетью машинами). Система почти полностью реализована в виде набора менеджеров объектов (например, файловая система, поддерживающая объекты-файлы), выполняющихся в непривилегированном режиме, часто в различных адресных пространствах, чтобы защититься от приложений (и от других менеджеров). Как следствие, добавить новую возможность к системе столь же легко, как и написать приложение в Spring, причем каждая такая возможность становится неотъемлемой частью распределенной системы.

Менеджеры объектов сами являются объектами: например, файловая система - это менеджер объектов, поддерживающий операцию открытия файла по имени. Объекты-файлы, которые он возвращает в качестве результата операции open, реализованы как часть того же менеджера, поскольку это удобно и делается естественно. Поскольку менеджер объектов подобен распространенному понятию сервера (например, файловый сервер) термины используемые в данной статье, взаимозаменяемы.

В оставшейся части статьи будут обсуждаться:

- IDL;
- модель и реализация объектов в Spring
- общая структура системы Spring;
- Spring Nucleus;
- реализация распределенного обращения к объектам, безопасность, виртуальная память, файловые системы, совместимость с UNIX, унифицированный именной сервис.

В заключение мы сформулируем некоторые выводы, основанные на нашем опыте в проектировании и реализации системы.

Язык Определения Интерфейсов (IDL)

Язык Определения Интерфейсов, разработанный в проекте Spring, по существу совпадает с IDL, принятым Object Management Group в качестве стандарта для определения распределенных объектно-ориентированных программных компонентов. Вследствие этого "компиляторы" IDL реализованы либо реализуются рядом компаний.

Что делает компилятор IDL? В конце концов, что компилировать, если интерфейсы не рассматриваются в качестве реализаций? Обычно компилятор IDL используется для порождения трех фрагментов исходного кода на некотором выбранном целевом языке реализации (например, С, С++, Smalltalk и т. д.):

1. Специфичная для выбранного языка форма IDL-интерфейса: для С и С++ это файл заголовков, содержащий определения на соответствующем языке методов, констант, типов и т. д., введенных в IDL-интерфейсе. Ниже мы рассмотрим пример.

2. Клиентская часть суррогатного кода: код, предназначенный для динамического связывания с клиентской программой, обращающейся к объекту, реализованному в другом адресном пространстве или на другой машине.

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

Три этих сгенерированных компилятором фрагмента кода позволяют реализациям, выполненным на конкретном языке, например, на С++, обращаться к определенным на IDL объектам, как если бы они были объектами на С++. Так, программисту, пишущему клиенты на С++, следует использовать транслятор IDL-C++ для порождения файлов заголовков и суррогатного кода для определения объектов в стиле С++. В то же самое время объекты могут быть реализованы на С, и поэтому для генерации серверной части суррогатного кода следует использовать транслятор IDL-С, что позволит трансформировать поступающие вызовы в обращения к С-функциям, работающим с С-объектами, соответствующими IDL-объектам.

Пример

Ниже приведен пример использования IDL для определения интерфейса ввода-вывода (IO) Spring. В нашем случае детали опущены, но пример основан на реальном применении IDL.

interface io {
raw_data read (in long size)
raises (access_denied, alerted,
falure, end_of_data)

void write (in raw_data data)
raises (access_denied, alerted,
incomplete_write, failure,
end_of_data)
};

Интерфейс определяет объекты типа IO. Над любым объектом IO определены две операции, read и write. Операция read имеет параметр size типа long и возвращает результат типа raw_data. Операция write возвращает пустой результат (void) и имеет один параметр data типа raw_data. Кроме обычного завершения обе операции могут привести к возникновению одной из нескольких определенных исключительных ситуаций.

Объекты в Spring

Хотя все интерфейсы Spring определены средствами IDL, IDL ничего не говорит о том, как реализуются операции над объектом, и даже о том, как запрос операции переправляется объекту.

Пользователи объекта просто вызывают операции, определенные в его интерфейсе. Как и где операция реально выполняется, решает реализация объекта. Иногда операция выполняется в том же самом адресном пространстве, где находится и клиент, иногда в другом адресном пространстве на той же машине, иногда - на другой машине.

Мы будем часто использовать фразу "вызвать объект" как короткую форму "вызвать операцию объекта"

Обьекты, основанные на серверах

Многие объекты в Spring реализуются в серверах, которые находятся в адресных пространствах, отличных от адресных пространтв клиентов. Для поддержки таких объектов используются автоматически генерируемые суррогаты (см. предыдущий раздел), которые берут аргументы вызовов этих объектов, выстраивая их для передачи серверу, а затем вновь перестраивают результаты и возвращают их приложению-клиенту. Для связи с удаленным сервером суррогаты используют предложенный нами механизм субдоговоров.

Обычно для взаимодействия между клиентом и сервером объекты, основанные на серверах, используют механизм Spring названный двери (doors). Большинство субдоговоров распознают случаи, когда клиент и сервер оказываются в одном адресном пространстве, и вместо стандартного связывания через ядро выполняют локальный вызов функции.

Объекты без серверов

Spring поддерживает также объекты без серверов, когда состояния объектов полностью находятся в адресном пространстве клиентов. Этот реализационный механизм подходит для простых "легковесных" объектов таких типов, как name или raw data. Когда же подобный объект передается между адресными пространствами, его состояние копируется в новое адресное пространство. Таким образом, это более напоминает передачу структуры, в то время как передача объекта, основанного на сервере, больше походит на передачу указателя на удаленное адресное пространство.

Субдоговор

Spring обеспечивает гибкий механизм для динамической реорганизации алгоритмов объектной среды времени выполнения. Данный механизм, называемый субдоговором, позволяет управлять тем, как выполнена реализация объектов, как передаются между адресными пространствами ссылки на объекты, как эти ссылки освобождаются, равно как и другими подобными объектными операциями времени выполнения [2].

Например, широко используемый одноточечный (single-ton) субдоговор обеспечивает простой доступ к объектам в других адресных пространствах. Когда клиент обращается к объекту с таким субдоговором, вызов реализуется посредством перенаправления запроса в то адресное пространство, где находится объект. Реализованы также субдоговоры, поддерживающие репликацию. Они поддерживают обращение к объектам посредством копирования запроса во все серверы, участвующие в поддержке тиражируемого объекта.

Кроме того, используются субдоговоры, реализующие ряд различных объектных механизмов времени выполнения, включая поддержку "дешевых" объектов, кэша и восстановления после сбоев.

Общая структура системы

Spring организована как микроядерная система. В режиме ядра выполняются Nucleus, управляющий процессами и межпроцессным взаимодействием, а также менеджер виртуальной памяти, который контролирует аппаратуру управления памятью. Nucleus связан с окружением посредством механизма прерываний. Менеджер виртуальной памяти обрабатывает прерывания по отсутствию страницы, но одновременно с этим предоставляет объекты для поддержки внешних систем страничной организации памяти и, в этом обличье, напоминает любой другой менеджер объектов.

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

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

Nucleus

Nucleus - это микроядро Spring. Оно поддерживает три базовые абстракции: домены (domain), нити (thread) и двери (door).

Домены аналогичны процессам в UNIX или задачам в Mach. Они обеспечивают адресное пространство, в котором выполняются приложения, и действуют как контейнеры для различного рода ресурсов приложений, таких как нити и двери.

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

Двери поддерживают объектно-ориентированные вызовы между доменами. Дверь описывает конкретную точку входа в домен, представляя ее счетчиком команд и уникальным значением, назначенным доменом. Это уникальное значение обычно используется сервером объектов для идентификации состояния объекта; например, если реализация выполнена на С++, значение может быть указателем на С++- объект.

Двери

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

Владение подходящей дверью дает владельцу право посылать в эту дверь запрос на обращение к объекту.

Получить же ее можно только с согласия соответствующего домена либо с согласия того, кто уже владеет идентификатором той же самой двери.

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

Благодаря дверям, Spring обеспечивает весьма эффективный механизм обращения к объектам, расположенным в разных адресных пространствах. Нить в одном адресном пространстве может обратиться через дверь к объекту в другом адресном пространстве, Ядро назначает нить сервера в целевом адресном пространстве и быстро переключает управление на эту нить, передавая ей информацию, ассоциированную с дверью, а также аргументы, указанные вызвавшей нитью.

Когда нить сервера хочет возвратить управление, ядро дезактивирует ее и вновь активирует вызвавшую нить, возвращая все результаты, указанные вызванной нитью.

В случае вызова с минимальным числом аргументов Spring может выполнить низкоуровневый вызов двери между адресными пространствами за 11 мкм на SPARCstation 2, что значительно быстрее, чем использование общецелевых механизмов межпроцессорного взаимодействия [1].

Двери могут передаваться как аргументы или результаты вызовов. Ядро создаст соответствующие элементы таблицы дверей для указанной двери в таблице получателя и сообщит для них идентификаторы дверей.

Сетевые посредники

Для того чтобы обеспечить вызов объектов по сети, механизм вызова расширен так называемыми сетевыми посредниками (network proxy), которые прозрачным образом соединяют ядра различных машин. Эти посредники являются обычными пользовательскими доменами-серверами и не имеют никакой специальной поддержки от ядра. Одна Spring-машина может содержать несколько доменов-посредников, "разговаривающих" на разных сетевых протоколах.

Посредники прозрачным образом продвигают обращения к дверям между доменами на разных машинах. Пример такого взаимодействия приведен на Рисунке 6: когда клиент на машине В обращается к двери У, это обращение поступает сетевому посреднику В; В продвигает вызов по сети своему собрату, посреднику А; А делает обращение к двери; и, наконец, обращение к двери прибывает в домен сервера.

Отметим, что ни клиенту, ни серверу не требуется знать наверняка, что посредники существуют. Клиент просто выполняет обычное обращение к двери, а сервер просто ожидает обычное поступающее обращение к двери.

Идентификаторы дверей преобразуются в специальные сетевые заголовки (network handle) перед передачей по сети, а после их передачи происходит обратное преобразование. Сетевой заголовок содержит сетевой адрес создавшего его посредника и набор бит, идентифицирующих конкретную дверь, экспортируемую этим посредником. Теоретически набор бит достаточно велик, чтобы превратить в непосильную задачу для злонамеренного пользователя отгадывание сетевого заголовка, что обеспечивает защиту от их подделки.

Модель безопасности Spring

Одна из целей Spring состоит в обеспечении безопасного доступа к объектам, то есть таких реализаций объектов, которые могут контролировать доступ к конкретным данным или сервисам. Для того чтобы обеспечить безопасность, мы поддерживаем два базовых механизма: Списки Контроля Доступа и программных мандатов.

Любой объект может поддерживать Список Контроля Доступа (ACL - Access Control List), определяющий, каким пользователям или группам пользователей разрешен доступ к данному объекту. Эти списки могут проверяться в процессе выполнения, чтобы определить, действительно ли данному клиенту разрешен доступ к данному объекту.

После того как установлено, что клиенту разрешен доступ к объекту, сервер объекта создает ссылку на обьект (object reference), которая действует как программный мандат. Данная ссылка используется дверью в качестве части своего представления, что не позволяет подделать ее злонамеренному пользователю. Дверь указывает на фронтальный объект (front object) внутри сервера. Фронтальный объект не является объектом в смысле Spring, его строение определяется языком реализации сервера.

Фронтальный объект инкапсулирует информацию, идентифицирующую того, кому выдан программный мандат и права доступа, которыми он обладает.

Данный сервер может создать много различных фронтальных объектов, инкапсулирующих различные права доступа, но указывающих при этом на один и тот же нижележащий объект. Затем, когда клиент обратится к объекту по ссылке на объект, запрос безопасным образом будет передан через дверь ядра и доставлен фронтальному объекту. После этого фронтальный объект, основываясь на инкапсулированных правах доступа, проверяет, правомочен ли данный запрос, и если это действительно так, продвигает запрос в сервер. Например, если клиент выдал запрос на обновление, фронтальный объект должен проверить наличие права на запись.

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

Допустим, например, что пользователь Х владеет объектом-файлом foo, список контроля доступа которого специфицирует, что только Х разрешено чтение файла. Но Х хотел бы распечатывать файл при посредстве принт-сервера Р. Р не указан в ACL для foo, поэтому, вообще говоря, он не может получить доступ к данным foo. Однако Х может получить ссылку на объект, действующую как программный мандат, инкапсулирующий право чтения foo, которым обладает Х. Затем Х может передать эту ссылку на объект принт-серверу Р, и Р сможет прочитать файл.

Использование программных мандатов в Spring облегчает для прикладных программ передачу объектов серверам таким образом, который дает серверам возможность реального использования этих объектов.

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

Spring реализует расширяемую систему виртуальной памяти с подкачкой страниц по требованию, которая отделяет возможность кэширования страниц от задач сохранения и извлечения страниц [7].

Обзор

Имеющийся на каждой машине менеджер виртуальной памяти (VMM - Virtual Memory Manager) управляет отображением, разделением, защитой, передачей и кэшированием локальной памяти. VMM использует внешние системы страничной организации памяти, илипейджеры (external pager), для доступа к вторичным запоминающим устройствам и поддержания межмашинной когерентности.

Большинство клиентов системы виртуальной памяти имеют дело только с такими объектами, как адресное пространство (address space) и память (memory). Первый объект представляет собой виртуальное адресное пространство домена Spring а второй - абстракцию памяти, которая может отображаться на адресные пространства. Пример объекта памяти - объект-файл (интерфейс файла в Spring наследуется из интерфейса объекта памяти). Объекты адресного пространства реализуются VMM.

Для объекта памяти предусмотрены операции установки и опроса длины, а также операция связывания (bind) с объектом. Операции типа read/write или page-in/page-out отсутствуют. Файловый интерфейс Spring предоставляет операции чтения и записи файла (но не операции над страницами). Отделение абстракции памяти от интерфейса, отвечающего за страничную организацию, - это особенность системы виртуальной памяти Spring которая оказалась весьма полезной при реализации файловой системы. Разделение позволяет располагать сервер объектов памяти на другой машине, нежели сервер страниц, который предоставляет содержимое объекта памяти.

Адресное пространство - это линейный диапазон адресов, области которого отображены на обьекты памяти. Каждая область отображается на обьект памяти (или на его часть). Каждая страница такой области может отображаться с установлением прав на чтение/запись/выполнение и может быть заблокирована в памяти.

Кэши и пейджеры

Для того чтобы обеспечить когерентное кэширование данных более чем одним VMM, необходимо установить двунаправленное соединение между VMM и внешним пейджером (в качестве которого может выступать, например, файловый сервер). VMM нуждается в соединении с внешним пейджером, которое позволило бы VMM получать и засылать данные, а внешний пейджер нуждается в соединении с VMM, которое позволило бы выполнять операции по установлению когерентности с VMM (например, чтобы объявить недостоверными данные, содержащиеся в кэше VMM). Это двунаправленное соединение представляется двумя объектами.

VMM получает данные, обращаясь к объекту, реализованному внешним пейджером, а внешний пейджер выполняет операции по установлению когерентности, обращаясь к объекту-кэшу, реализованному VMM.

Когда VMM запрашивает отображение объекта памяти в адресное пространство, VMM должен получить доступ к объекту-пейджеру, что позволит ему манипулировать данными объекта. С этим объектом-пейджером должен быть ассоциирован объект-кэш, который внешний пейджер сможет использовать для установления когерентности.

VMM нуждается в механизме, который гарантировал бы, что два эквивалентных объекта памяти (например, два объекта, ссылающиеся на один и тот же дисковый файл) при отображении будут разделять данные, содержащиеся в кэше VMM. Для того чтобы добиться этого, VMM применяет к объекту памяти операцию связывания. Данная операция возвращает объект cache_rights, реализованный самим VMM. В случае отображения двух эквивалентных объектов памяти, будет возвращаться один и тот же cache rights. VMM использует данный объект для поиска соединения пейджер-кэш, а также для того, чтобы найти все кэшированные страницы объекта памяти.

Когда объект памяти получает от VMM операцию связывания, он должен определить, установлено или нет соединение пейджер-кэш для данного VMM. Если соединение отсутствует, внешний пейджер, реализующий объект памяти, контактирует с VMM, и они обмениваются объектами: кэшем; пейджером и cache rights. Если же соединение уже установлено, объект памяти возвращает VMM соответствующий объект cache rights.

Как правило, между данной парой пейджера и VMM имеется одновременно много каналов пейджер-кэш.

Поддержание когерентности данных

Задача поддержания когерентности данных между различными VMM, использующими кэши для объекта памяти, решается внешним пейджером, который реализует данный объект памяти. Протокол когерентности не специфицирован в архитектуре - внешние пейджеры свободны реализовать такой протокол, какой пожелают. Интерфейсы объектов кэша и пейджера предоставляют базовые строительные блоки для конструирования протокола когерентности. Текущие реализации внешних пейджеров используют поблочный протокол когерентности типа "один-пишет/многие-читают" [11, 13].

Файловая система

Архитектура файловой системы определяет объекты файлы, которые реализуются файловыми серверами. Интерфейс файлов наследуется у интерфейсов ввода-вывода иобъектов памяти. Поэтому объекты-файлы могут отображаться в память (поскольку одновременно они являются объектами памяти), а также к ним возможен доступ с использованием операций чтения/записи интерфейса ввода-вывода.

Spring включает файловые системы, допускающие доступ как к файлам на локальных дисках, так и по сети. Каждая файловая система использует архитектуры обеспечения безопасности и управления именами Spring для контроля доступа и служб каталогов.

Как правило, файловая система Spring состоит из нескольких разбитых на уровни файловых серверов [5]. Описанная выше парадигма объектов пейджер-кэш используется файловыми системами в качестве общего механизма разбиения на уровни между различными файловыми серверами и менеджерами виртуальной памяти. Кроме прочего, это позволило, благодаря сохранению данных и атрибутов в связанных с каждой машиной кэшах, уменьшить число обращений по сети к удаленным файлам.

Реализации файловых серверов

Реализация файловой системы Spring (Storage File System - SFS) выделяет два уровня.

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

Второй уровень реализует поблочный протокол когерентности типа "один-пишет/многие-читают". Кроме прочего, этот слой в каждый момент времени отслеживает состояние каждого файлового блока ("только-чтение" либо "чтение-и-запись") и каждого объекта-кэша, содержащего блок. Действия по поддержанию когерентности запускаются протоколом в зависимости от состояния и от текущего запроса. Слой когерентности помещает в кэш также и атрибуты файлов.

Caching File System (CFS) - это файловая система с кэшированием. Ее основная задача - вклиниться между локальными клиентами и удаленными файлами, когда последние передаются на локальную машину, чтобы тем самым увеличить эффективность многих операций. При наличии такой файловой системы все вызовы удаленных файлов обрываются, оказываясь перехваченными локальной CFS.

Интересный аспект CFS состоит в том, как она динамически вклинивается в индивидуальные удаленные DFS-файлы. В процессе разворачивания объектов-файлов для контакта с локальной CFS используется субдоговор кэширования. Когда CFS надо вклиниться в файл, она становится менеджером кэша для удаленного файла, выполняя над файлом операцию связывания.

Механизм именования Spring

В операционной системе имеются различные виды объектов, которым необходимо дать имена: пользователи, файлы, принтеры, машины, сервисы и т. д. Большинство операционных систем предоставляют сразу несколько именных сервисов, каждый из которых приспособлен к определенному виду объектов. Подобные зависящие от типа именные сервисы обычно встраиваются в подсистему, реализующую такие объекты. Например, файловые системы реализуют свой собственный сервис для именования файлов (и каталогов).

Spring, напротив, предоставляет унифицированный именной сервис [17]. В принципе, любой объект можно связать с любым именем. Сервис применим, если объект является локальным для процесса, для машины или располагается где-либо в сети, вне зависимости от того, является ли он временным или хранимым; им можно воспользоваться, если речь идет о стандартном системном объекте, об объекте окружения процесса или специфическом объекте пользователя. Именные сервисы и пространства имен не надо разделять по типу объекта. Разные пространства имен можно объединять, создавая тем самым новые пространства имен.

Благодаря общему именному сервису, мы снимаем с клиентов бремя забот об использовании различных имен или различных именных сервисов в зависимости от того, к каким объектам происходит доступ. Аналогичным образом мы снимаем со всех реализаций объектов бремя забот о конструировании пространства имен - именной сервис обеспечивает средства для интеграции новых видов объектов и новых реализаций уже существующих объектов в Spring Впрочем, хотя Spring и предлагает общий именной сервис и именной интерфейс, архитектура системы позволяет использовать в качестве частей именного сервиса различные серверы имен с различными свойствами реализации.

Именной сервис позволяет ассоциировать объект с именем в некотором контексте (context), также объекте специального вида, который содержит набор ассоциаций имя-объект, или связываний имен (name bindings), и используется клиентами для выполнения всех операций над именами. Объект может быть одновременно связан с несколькими различными именами в различных контекстах. С другой стороны, объект может быть не связан ни с каким именем.

Посредством связывания контекстов в других контекстах мы можем создать граф именования (naming graph) , неформально называемый пространством имен - направленный граф с узлами и помеченными ребрами, где узлы с исходящими из них ребрами соответствуют контекстам.

В отличие от схем именования в традиционных системах, контексты и пространства имен Spring являются объектами первого класса: к ним можно получать доступ и манипулировать ими непосредственно. Например, два приложения могут обменяться и коллективно использовать частные пространства имен. Традиционно таким приложениям пришлось бы построить свою собственную систему именования или включить частное пространство имен в более крупную систему - широкое пространство имен, доступ к которому осуществляется косвенно, через корневой или рабочий контекст.

Поскольку объекты Spring по умолчанию, не являются хранимыми, именование используется для реализации хранимых объектов [16]. Предполагается, что приложения в общем случае будут (заново) получать объекты из именного сервиса. Если часть пространства имен, в котором найден объект, является хранимой, то хранимым будет и сам объект.

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

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

Именной сервис Spring не предписывает какой-либо определенной стратегии именования; над ним можно надстроить различные стратегии. Принятая в настоящий момент стратегия должна обеспечивать сочетание предоставляемых системой разделяемых пространств имен, пользовательских пространств имен и пространств имен доменов, которое может настраиваться посредством подсоединения пространств имен в различных частях распределенной среды.

По умолчанию, при запуске каждый домен получает от своего "родителя" частное пространство имен домена, которое содержит пользовательское и системное пространства имен. Если пожелает, домен может получить и другие пространства имен и контексты.

Эмуляция ОС UNIX

Используя подсистему эмуляции UNIX, Spring может исполнять двоичные файлы Solaris [6]. Подсистема эмуляции целиком реализована на пользовательском уровне, не пользуется "настоящим" кодом UNIX и обеспечивает двоичную совместимость для большого набора программ Solaris. Подсистема использует сервисы, уже предоставляемые нижележащей системой Spring и реализует только специфичные для ОС UNIX средства, которые не имеют эквивалентов в Spring (например, сигналы). Для того чтобы реализовать эмуляцию Solaris, не потребовалось никаких модификаций в самой системе Spring.

Реализация состоит из двух компонентов: разделяемой библиотеки (libue.so), которая динамически связывается с каждым двоичным файлом Solaris, и набором специфичных для UNIX сервисов, реализованных в рамках отдельного домена сервером UNIX-процессов и экспортируемых объектами Spring.

Сервер UNIX-процессов реализует функции, которые не являются частью базовой системы Spring и которые нельзя поместить в libue.so по соображениям, связанным с безопасностью.

Libue

Когда программа запускается посредством ехес, libue.so динамически связывается с образом приложения вместо libc, позволяя тем самым исполнять приложение, не изменяя его.

Библиотека libue.so содержит некоторые функциональные возможности, обычно помещающиеся в монолитное ядро UNIX. В частности, она реализует сигналы, используемые сервером UNIX-процессов, и отслеживает связь между дескрипторами файлов UNIX (fd) и объектами-файлами Spring.

Для каждого системного вызова UNIX в библиотеке реализован суррогат. В общем случае существует три вида вызовов:

1. Вызовы, которые просто получают аргументы наподобие fd, разбирают все переданные флаги и обращаются к сервису Spring (например, read, write, mmap - отображение объекта памяти). Большинство операций файловой системыи виртуальной памяти попадают в эту категорию.

2. Вызовы, которые, в конечном счете, обращаются к специфичному для UNIX сервису, реализованному сервером UNIX-процессов. Примеры включают pipe и kill.

3. Вызовы, которые изменяют локальное состояние, не обращаясь к другому домену. В зту категорию попадают dup, часть fcntl и многие вызовы, связанные с обработкой сигналов.

Сервер UNIX-процессов

Сервер UNIX-процессов поддерживает взаимоотношения предок-потомок между процессами, отслеживает идентификаторы процессов и групп процессов, поддерживает сокеты и каналы, передает сигналы.

Сервер UNIX-процессов участвует в ветвлении и смене исполняемого образа новых процессов. Кроме того, он участвует в продвижении (но не в выдаче) сигналов. Поскольку он отслеживает идентификаторы процессов и групп, он при необходимости отвейает за поддержку свойственной UNIX семантики безопасности для процессов-клиентов.

Выводы

В проекте Spring было решено построить операционную систему, отличную от уже существующих, основанную на таких понятиях, как строгие интерфейсы, открытость и расширяемость, и рассчитанную на распределенные среды и на многопроцессорные платформы. Использованные идеи объектно-ориентированного подхода и строгих интерфейсов естественным образом дополнили друг друга и обеспечили ряд преимуществ:

- стандартизованный базис для открытых, распределенных объектных систем: Язык Определения Интерфейсов и простая клиентская модель для объектов;

- легкая организация распределенных сервисов и приложений;

- быстро расширяемые системные средства, такие как файловые системы и именные сервисы;

- единство архитектуры вместе с широким спектром средств, упрощающих реализацию: управление виртуальной памяти, именование, субдоговоры и объекты без серверов;

- высоко зффективное обращение к объектам между адресными пространствами, поддерживающее микроядерную архитектуру.

Наконец, начатое с самого начала проектирование механизмов обеспечения безопасности позволило создать систему, которая может обеспечить широкий диапазон механизмов защиты в сетевой среде - от самой слабой до самой безопасной.


Литература

[1] Graham Hamilton and Panos Eougiouris, "The Spring Nucleus: А Microkernel for Objects", Proc. 1993 Summer USENIE Conference, pp.l47-1бО, June 1993.

[2] Graham Hamilton, Michael L.Powell,and James G.Mitchell, "Subcontract А Flexible Base for Distributed Programming", Proc. 14th АСМ Symposium on Operating Systems Principles, рр.69-79, December 1993.

[3] Graham Hamilton and Sanjay Kadia, "Using Interface Inheritance to Address Problems in System Software Evolution", Ргос. АСМ Workshop on Interface Definition Languages, January 1994.

[4] Peter B.Kessler, "А Clien1-Side Stub Interpreter, Proc. АСМ Workshop on Interface Definition Languages, January 1994.

[5] Yousef A. Khalidi and Michael N. Nelson, "Extensible File Systems in Spring", Proc. 14th АСМ Symposium on Operating Systems Principles, рр. 1-14, December 1993.

[6] Yousef A.Khalidi and Michael N.Nelson, "An Implementation of UNIX on an Object-oriented Operating System", Proc. Winter 1993 USENIX Conference, рр.469-479, January 1993.

[7] Yousef A.Khalidi and Michael N.Nelson, "The Spring Virtual Memory System", Sun Microsystems Laboratories Technical Report SMLI-93-9, March 1993.

[8] Yousef A.Khalidi and Michael N.Nelson, "А Flexible External Paging Interface", Proc. 2nd Workshop on Microkernels and Other Kernel Architectures, September 1993.

[9] Michael N.Nelson and Graham Hamilton, "High Performance Dynamic Linking Thnough Caching", Proc.1993 Summer USENIX Conference, pp.253-266, June l993.

[10] Michael N.Nelson, Graham Hamilton, and Yousef A.Khalidi, "Caching in an Object-Oriented System", Proc. 3rd International Workshop on Object Orientation in Operating Systems (I-WOOOS 111), pp 95-106, December 1993.

[II] Michael N.Nelson and Yousef A.Khalidi, "Generic Support for Caching and Disconnected Operation, Proc. 4th Workshop on Workstation Operating Systems (WWOS-IV), рр. б1-65, October 1993.

[12] Michael N.Nelson, Yousef A.Khalidi, and Peter W. Madany, "Experience Building а File System on а Highly Modular Operating System", Proc. 4th Symposium on Experiences with Distributed and Multiprocessor Systems (SEDMS IV), September 1993.

[13] Michael N.Nelson, Yousef A.Khalidi, and Peter W. Madany, "The Spring File System", Sun Microsystems Laboratories Technical Report SMLI-93-10, March 1993.

[14] Michael N.Nelson and Sanjay R.Radia, "А Uniform Name Service for Spring's Unix Environment", Proc. Winter 1994 USENIX Conference, Jan. 1994.

[15] Objekt Management Group, "Common Object Reguest Broker Architecture and Specification", OMG Document 91.12.1, December 1991.

[16] Sanjay Radia, Peter Madany, and Michael L.Powell, "Persistence in the Spring System", Proc.3rd International Workshop on Object Orientation in Operating Systems (1-WOOOS III), рр. 12-23, December 1993.

[17] Sanjay R.Radia, Michael N.Nelson, and Michael L.Powell, "The Spring Name Service", Sun Microsystems Laboratories Technical Report SMLI-93-16, 0ctober 1993.