Изнутри Mach. Менеджер памяти

Дата: 29/06/05;  Автор: CodeWorld; 


Mach - это одна из первых микроядерных unix систем, корни которой засели в далеких 70-х годах. Своё сегодняшнее название ОС получила в университете Карнеги-Мэллоуна (в середине 80-х) с введением в ядро IPC и существенными изменениями тогдашней архитектуры системы. Нельзя не согласиться, что за такое время mach набралась огромного опыта. Или можно? Сегодня мы попробуем на это ответить!

Менеджер памяти в mach состоит из 2-х частей. Внутренний менеджер памяти включает мапер, зависящий от конкретной архитектуры MMU и машинно-независимый обработчик страничных отказов с нехитрой логикой подмены и отображения заранее подготовленных страниц. Основные алгоритмы (в том числе подготовка страниц для внутренного менеджера памяти) находятся во внешнем менеджере памяти, который исполняется как обычный пользовательский процесс. Прежде чем продолжить надо сказать, что в mach существует ключевое понятие объекта памяти. Абстракция "объект памяти" это набор специально сформированных страниц. Они могут хранить произвольные данные, быть чистыми, а могут содержать и считанный файл (именно на этом построен механизм отображение файлов в память). Главная задача внешнего менеджера памяти (далее просто менеджера памяти) заключается как раз в управлении объектами памяти - отображение, создание, удаление, свопинг и возвращение обратно в память. Менеджеров памяти может быть несколько, обычно так оно и есть - для каждого класса объектов памяти свой менеджер. Мы приведём лишь два: менеджер отображения файлов и менеджер по умолчанию (управляет обычной пользовательской памятью). Для работаспособности каждому объекту памяти создается три порта, но для нас важны только два - порт объекта и порт управления. Перейдём к функционированию...
Если происходит страничный отказ, ядерный (внутренний) менеджер памяти определяет ответственный объект памяти за диапозон виртуальных адресов вызваших сбой. В порт объекта посылается запрос на предоставление отсутвующей страницы, а в это время на другом конце одна из нитей внешнего менеджера памяти (обрабатывающая интересующий нас объект) заблокирована в ожидании сообщений на свой порт объекта. Ядро отправляет сообщение с запросом и блокирует свой ядерный поток в ожидании ответа, а менеджер памяти просыпается, обрабатывает запрос и посылает ответ на порт управления об завершении операции, ядерный поток просыпается и выполнение прерванного процесса продолжается.



При такой модели каждый объект памяти обрабатывается индивидуальным потоком какого-то менеджера памяти (на рис. изображен только один менеджер памяти с нескольками потоками). Между ядром и потоком установлена прямая двух сторонняя связь осуществляемая двумя портами - в порт управления пишет менеджер памяти ядру, в порт объекта наоборот. Нетрудно догадаться, что объектов памяти в работающей системе может быть свыше 3-х сот! Легкими подщётами (300*2) можно увидеть сумашедшее число портов - свыше 600! Это всё ядерные структуры, ядерный трафик, расходы памяти... А с учетом того, что менеджеров памяти может быть несколько - это большое число контекстов, которые можно было избежать. В те года еще не были утверждены динамические библиотеки, которые являются наилучшим решением данной ситуации!
Первое, что я предлогаю, так это внести все менеджеры памяти в единый контекст, это можно легко сделать с помощью использования механизмов DLL. Теперь займёмся формулировкой задачи! Нам нужно установить взаимодейтвие между менеджером памяти и ядром, в обоих направлениях. В порты объектов пишут ядерные потоки, в порты управления пишут потоки менеджера памяти. Порты управления можно действительно оставить в количестве равном ядерным потокам, это в силу архитектуры mach. Но я бы усыплял ядерные потоки без условий - менеджер памяти сам сообщит, то что запрос такой-то выполнен, ядро разбудит ждущий поток. В существующей mach ядерные потоки усыпляются при ожидание ответа на порт управления, поэтому ладно - у нас несколько портов управления. А вот нащёт порта объекта, его бы следовало сделать одним. Для этого придётся изменить совсем чуть-чуть спецификацию протокола взаимодейтсвия. Тогда набрасываем новую модель функционирования менеджера памяти. Главный поток менеджера памяти как командир забирает все задания и раздаёт их своим подручным (потокам) в зависимости от внутренний политики (здесь можно тоже изобрести оптимальные решения). Из-за того, что задания принимаются одним потоком не которые могут увидеть здесь очередь. Ничего подобного! За один квант главный поток менеджера памяти может раздать задания 200 потокам. Так же полностью исключается инверсия - потоки менеджера памяти будут работать на приоритете запросов. Теперь о том как раздаются задания и будятся потоки. Главный поток менеджера памяти читает сообщения прямо в адреса разделямой памяти, пробуждаются потоки по событиям. Каждый поток знает в какой ячейке лежит его задание. Теперь посмотрим, что же мы получили? Порт объектов будет жестко закэширован, уменьшено использование памяти, смена контекстов сведена к минимуму. И все это мы сделали, что бы поднять производительность! ;)



Mach была мощной операционной системой - она справлялась с поставленными задачам и продолжает это делать сейчас, однако уже не самыми эффективными способами. Mach больше не идёт в ногу со временем, но продолжает жить в OSF/1, NeXT и Mac OS X!