Библиографическое описание:

Симоненко Д. Н. Компонентно-безъядерная архитектура операционной системы [Текст] // Технические науки: проблемы и перспективы: материалы междунар. науч. конф. (г. Санкт-Петербург, март 2011 г.). — СПб.: Реноме, 2011. — С. 149-153.

Компонентно-безъядерная архитектура является техническим решением, разработанным и примененным нами при проектировании и реализации операционной системы Outra.

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

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

Архитектура ОС Outra имеет объектно-ориентированную природу и по сути, является дальнейшим развитием монолитной и микроядерных архитектур. Архитектура ОС получила название Компонентно-безъядерной.

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

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

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



Рис. 1. Сравнение монолитно-модульной и компонентно-безъядерной

архитектур

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

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

Данная архитектура реализуется путем добавления некоторых дополнительных элементов на этапе загрузки. Рассмотрим этот процесс подробнее на примере реализации загрузки операционной системы Outra (для архитектуры IBM PC) (см. рис. 2).

При запуске компьютера BIOS считывает (при условии загрузки с жесткого диска) первый сектор загрузочного диска, который называется MBR (главная загрузочная запись). Этот сектор содержит минимальную программу загрузки вместе с таблицей разделов жесткого диска. Эта программа определяет (обычно активный, или интерактивно) раздел для дальнейшей загрузки. После выбора раздела загрузки, считывается первый сектор этого раздела, который представляет вторичную программу загрузки boot. В отношении операционной системы outra, этот загрузчик знает размеры (они подсчитываются и записываются непосредственно во вторичный загрузчик после сборки системы) третьего загрузчика. После загрузки с диска в память, вторичный загрузчик передает управление третьему загрузчику.














Рис. 2. Загрузчик ОС Outra

Третий загрузчик является основным загрузчиком в системе, который уже непосредственно занимается загрузкой самой операционной системы. В отношении операционной системы outra и специфики её архитектуры, он имеет важное значение. Загрузчик представляет из себя фундамент всей архитектуры (в операционной системе outra он называется ground. Давайте рассмотрим процесс дальнейшей загрузки и важные составляющие загрузчика.

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

Задачей корневого менеджера памяти (mm)(как и вообще менеджера памяти) является корректный учет использования диапазонов памяти, то есть операции выделения и освобождения блоков и диапазонов памяти (см. рис. 3). При этом должны учитываться функциональные особенности, при которых работа менеджера памяти должна осуществляться. Например, в системах массового обслуживания, сетевой подсистеме, учет и выделение новых пакетов данных должен осуществляться максимально быстро, нежели чем в других, менее зависимых от времени задачах. Поэтому, важно иметь возможность выбора необходимого метода, алгоритма выделения/освобождения памяти, который бы наиболее подходящим образом соответствовал специфики поставленной задачи. Другими словами политики, и способов специализированного управления ресурсами (эта проблема рассматривалась выше).

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

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






Рис. 3. Организация менеджера памяти


При инициализации менеджера памяти создается единственный корневой пул памяти (root), пределом, которого ставится размер доступной физической памяти, которая также определяется при инициализации.

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

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

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

После создания системы, на этапе сборки, модули формируются в специальную загрузочную файловую систему orofs (Outra object filesystem) (см. рис. 4). Она имеет достаточно простую, последовательную структуру, состоящую из суперблока, который содержит информацию о размере, количестве блоков, каталога модулей, содержащего названия, тип, размер и указатель на данные, и собственно самих данные, распределенных по блокам.





Рис. 4. Организация менеджера памяти


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

Следующим инициализируемым элементом является таблица классов (itable). Таблица классов необходима для учета пространств имен, классов и ассоциированных методов, анализа зависимостей, итп.

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

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

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

Методы объявляются очень просто, с помощью соответствующего именования методов в исходном коде, для чего (специально для языка Си) используется специальные макросы. Например, для объявления метода printf в пространстве имен lib и классе c, достаточно объявить функцию следующим образом:


INTERFACE(lib, c, printf)(const char * format, …) { }

Чтобы получить доступ к объявленному методу, другие модули могут его просто вызвать, путем записи:

METHOD(lib, c, printf)("Hello World");

После анализа методов, редактор связей, используя таблицы релокации модулей, анализирует зависимости разных модулей. Также, модулям, кроме интерфейсных вызовов (то есть вида METHOD(a, b, c)()), запрещается оставлять внешние ссылки. Таким образом, достигается строгая инкапсуляция. Помимо специализированных и расширенных свойств, функциональность редактора связей во многом аналогична редактору связей в компиляторе.

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

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

Для поддержки и сопровождения этой архитектуры, в операционной системе outra была создана специальная система сборки. Её работа заключается в создании зависимостей между отдельными множествами модулей. Сначала, в специальном конфигурационном файле описываются модули, которые должны быть включены в систему, для этого используется несложный язык описания. Далее, для каждого декларированного модуля, рекурсивно проверяются зависимости других модулей, итп. В конечном итоге создаются файлы сборки (Makefile's), соответствующие текущим параметрам создаваемой системы.

Заключение

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

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

На основе идей компонентно-безъядерной архитектуры и полученного опыта, была развита концепция единой отказоустойчивой среды выполнения[1]. Создан специализированный язык программирования и среда выполнения[2]. В настоящее время происходит адаптация новых подходов к современным требованиям и их аппробация.


Литература:
  1. Симоненко Д.Н. «Концепция единой отказоустойчивой среды выполнения» // Сборник научных трудов НТЦ РУП МЭСИ №6

  2. Симоненко Д.Н. «Архитектура и реализация единой отказоустойчивой среды выполнения.» // Сборник научных трудов НТЦ РУП МЭСИ №6

Обсуждение

Социальные комментарии Cackle