Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Разработка операционных систем - для начинающих и не только!


Информационный Канал Subscribe.Ru

Разработка операционных систем

Выпуск 16 от 2003-06-18

Сегодня в номере:

Микроядерная архитектура ядра ОС

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

Что же представляет из себя микроядро? Оно состоит из небольшого (как правило) набора абстракций, которые не составляют ОС сами по себе, но позволяют реализовать ОС в виде серверов, которые будут использовать предоставляемые микроядром сервисы. Например, микроядро Mach предоставляет следующие абстракции: задачи, потоки, объекты памяти, порты и сообщения. Все! Этого достаточно, чтобы построить на их базе полноценную операционную систему лишь с помощью тех частей, которые будут работать в пользовательском режиме

Как правило, абстракции, предоставляемые ядром, являются ОС-нейтральными. Это значит, что на их базе можно создать множество разных и очень сильно различающихся между собой операционных систем (в том числе можно и портировать на микроядро существующие системы с монолитным ядром; к примеру, Apple когда-то портировала Linux на микроядро Mach для использования на PowerMac, также существует проект Linux на L4).

Кстати, название "микроядро" подразумевает малый размер ядра (еще бы, ведь оно предоставляет гораздо меньше сервисов, чем монолитное), но важно отметить, что малый размер - лишь следствие, и многие (большинство) микроядра достаточно объемны. Но все же встречаются приятные исключения, например, Neutrino (микроядро систем QNX), а микроядро L4 занимает в памяти всего лишь 32Кб.

Обратите внимание, что разница между пользовательскими приложениями и компонентами ОС, работающими в пользовательском режиме чисто условна. Принято считать, что сервер ОС отличается от приложения тем, что он предоставляет какие-либо услуги приложениям (на то он и сервер).

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

Какие же преимущества у микроядерных систем?

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

Самые сообразительные читатели уже наверняка догадались, что же является главным в микроядре. Конечно же, это механизмы межпроцессного взаимодействия, или IPC (InterProcess Communication). Микроядро в своем идеальном проявлении состоит только из средств IPC (взаимодействие приложений с ядром тоже осуществляется при помощи тех же средств)

Выше приведено много теории, и хотелось бы рассмотреть все это на примере какого-нибудь микроядра?

Без проблем :) Давайте подробно рассмотрим применение микроядерных концепций на примере микроядра операционной системы Tyros, в разработке которого ваш покорный слуга непосредственным образом участвует.

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

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

Что еще должно быть в микроядре кроме IPC? Ответ "ничего" - неправильный, должны быть как минимум средства выделения ресурсов (хотя они тоже могут предоставлять свои возможности через IPC), поскольку серверам могут требоваться ресурсы компьютера, к которым нет доступа из пользовательского режима. Здесь мы не стали использовать идеальную концепцию (возможно так будет в следующей версии), но это, в принципе, не важно, а важно то, что сервера могут во первых, обратиться к системной области памяти (недоступной для пользовательских процессов), а во вторых - взаимодействовать с портами ввода вывода. Даже не обратиться, а попросить возможность обратиться. Важно, что каждый сервер получает в свое распоряжение лишь те системные ресурсы, которые ему нужны (в отличие от традиционной монолитной структуры ядра, где сбой в драйвере видеокарты может легко повесить всю систему), а значит, что ошибки в его работе (возникшие по недосмотру программиста) некритичны для работы системы

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

Как реализуется второе преимущество - стабильность и безопасность?

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

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

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

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

void main()
{
  int tty_attribute, tty_cursor;
  message_t msg;

  //Запросим доступ к видеопамяти
  ureq_sys_mem(VIDEO_RAM, 2, 0);
  //Стандартная последовательность инициализации
  tty_attribute = 7;
  tty_cursor = 0;
  clear(&tty_attribute, &tty_cursor);
  //Зарегистрируемся на системном сервере имен под именем 'console'
  //(теперь любая программа может выполнить open("console")
  //чтобы получить возможность посылать нам сообщения)
  msg.header = MSG_REGISTER_NAME;
  msg.pdata = "console";
  msg.size = 10;
  usend_msg(NAMESERVER, &msg, 0);

  puts("console driver is ready\n", &tty_attribute, &tty_cursor);


  //Цикл получения сообщений
  for(;;){
    //Подождем прихода сообщения
    uwait_msg();
    //Получим сообщение в структуру msg
    urecv_msg(&msg, 0);
    //Проанализируем заголовок сообщения
    switch(msg.header) {
    //если это MSG_WRITE
    case MSG_WRITE:
      //И если сообщение не пустое
      if(msg.size > 0) {
        //то выведем его на экран
puts(msg.pdata, &tty_attribute, &tty_cursor);
      }
      break;
    //если это MSG_CLEAR
    case MSG_CLEAR:
      //то очистим экран
      clear(&tty_attribute, &tty_cursor);
      break;
     }

  }
}

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

Вы уже прониклись великой мощью микроядерного подхода? :)

Outro

На сегодня все, уважаемые подписчики.
Как всегда, мой почтовый ящик открыт для вас:
lonesome@lowlevel.ru
Также вы можете задавать интересующие вас вопросы в форуме lowlevel.ru
Предыдущие выпуски рассылки вы можете найти по этому адресу:
http://subscribe.ru/archive/comp.soft.prog.osdev
А все, исходники, опубликованые в рассылке, располагаются здесь:
http://www.lowlevel.ru/osdev/sources.htm
Всего наилучшего!
Lonesome



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное