С первой болезнью научились бороться посредством модульного подхода: многие части ядра, обеспечивающие работу отдельных внешних устройств (т.н. драйверы устройств) или ядерных сервисов (в Linux их подчас также называют драйверами, например, драйвер файловой системы «имя рек»), могут не встраиваться жестко в исполняемый файл – образ ядра, а подключаться к нему в виде внешних модулей. И ныне ядра всех активно развивающихся UNIX-подобных систем, таких, как Linux или BSD, являются модульно-монолитными (подчас их для краткости называют и просто модульными).
Внешние модули могут как загружаться в память при старте системе, так и подгружаться в работающей системе, по необходимости. Нередко они обладают и способностью выгружаться, когда эта необходимость пропадёт. Однако в любом случае модули функционируют в пространстве ядра, так что их введение проблемы общей устойчивости не решает: криво написанный драйвер устройства все равно сохраняет способность обрушить систему. А поскольку, как уже говорилось, сложность кода ядра растёт, возрастает и вероятность появления ошибок, в том числе и критичных для работы системы.
Один из «косметических» вариантов решения проблемы был предложен Мэттом Диллоном и реализован им в системе DragonFlyBSD, о которой рассказывалось в предыдущей главе. Прошедшие с её появления годы доказали жизнеспособность этой реализации. Однако проблемы «большого» монолитного ядра это не снимало.
Для кардинального решения проблемы устойчивости ядра и были придуманы микроядра. Идея их – в том, чтобы, по словам Таненбаума, «вынести ядро за пределы ядра». То есть оставить в ядре только средства управления базовой аппаратурой, а драйверы устройств и сервисы выделить в отдельные программы, функционирующие в пользовательском пространстве памяти. При необходимости они обращаются к функциям ядра через специальные процедуры, но влиять на него каким-либо образом не могут. Такой подход приводит к повышению надежности системы, но снижает производительность, поскольку требует дополнительных накладных расходов.
Собственно, идея микроядра появилась очень давно, чуть ли не одновременно с самыми первыми UNIX'ами. Однако долгое время производительность машин не позволяла эффективно использовать микроядра в составе практически применяемых систем. Тем не менее, различных их реализаций было создано очень много. Время от времени то или иное микроядро пропагандировалось как основа операционной системы будущего, но удачных реализаций законченных микроядерных систем оказалось довольно мало.
Среди удачных решений на базе микроядра наибольшей известностью пользуется QNX. Правда, эта система лишь недавно начала то приоткрывать свой код, то закрывать его обратно, и потому об её устройстве известно немного. Да и как ОС общего назначения она никогда не позиционировалась.
Из свободных микроядерных реализаций наибольшую известность приобрело микроядро Mach, разрабатывавшееся вплоть до второй половины 90-х годов университетами – сначала Карнеги-Меллона, а затем штата Юта. Различные его версии в разное время составляли основу законченных систем, как свободных – BSD Mach (она же xMach) или Yamitt, так и проприетарных – NeXT и продолжившей её дело MacOS X. Все они имели в своем составе микроядро Mach, поверх которого запускалась драйверно-сервисная часть от ядра BSD, собранная в виде отдельного модуля.
Впрочем, из всех перечисленных систем только BSD Mach можно назвать по настоящему микроядерной, так как у него BSD-окружение ядра функционировало в пользовательском пространстве. И у NeXT, и у MacOS X BSD-окружение запускалось в том же пространстве ядра, так что микроядерными их можно назвать только по имени. А Yamitt в том виде, в каком я её наблюдал, просто не запускалась вообще.
Наконец, как мы видели, начиная с 1987 года и по настоящее время существует MINIX 1/2, основанная на собственной реализации микроядра. Каковую, в рамках очерченных для ннеё задач, можно считать удачной. А вот будет ли сопутствовать удача её потомку – микроядру нашей героини, MINIX 3, рассудит история.
Для начала заметим, что Таненбаум, по его же словам, не ставил самоцелью создание именно микроядерной ОС: задачей его команды было просто построение системы надежной и безопасной. Другое дело, что решение этой задачи им всегда виделось именно в микроядерной архитектуре. Почему он и предложил таковое, причем в виде, кардинально отличающемся от всех предлагавшихся ранее реализаций.
Читать дальше