Kernel review
В этой статье содержится краткий обзор архитектур разных типов ядер.
Содержание
Общая информация
Основными типами ядер являются следующие: монолитные ядра, микроядра и экзоядра.
В основном, они различаются компоновкой подсистем по отношению к ядру.
Ядро – это главная часть операционной системы. обладающая максимальными привилегиями. Она обеспечивает инфраструктуру для исполнения программ пользователя (пользователей): распределение памяти, процессорного времени, управляет вводом-выводом на устройства, обеспечивает средства для взаимодействия различных программ между собой.
Ядро исполняется с максимальными привилегиями, для компонентов ядра нет защиты памяти, они исполняются в едином адресном пространстве ядра и любой сбой в каком-то из компонентов ядра имеет фатальные последствия, может повредить другие компоненты, и поэтому обычно, ведет к остановке работы компьютера. Такая ситуация называется "Паникой ядра".
Зато компоненты пространства пользователя исполняются в отдельных адресных пространствах, на них действует аппаратная защита процессора и сбой в одном пользовательском процессе не затрагивает другие процессы. Сбой процесса пространства пользователя ведет к остановке только той программы, которая вызвала сбой.
Типы архитектур ядер операционных систем
Монолитное ядро
Первоначально большое число компонентов ОС принято было включать в состав ядра. И планировщик процессов, и менеджер памяти, и файловые системы, и драйверы для улучшения производительности включали в состав ядра. Такие ядра принято называть монолитными. Наиболее известное ядро такого типа -- классическое ядро UNIX. Оно статически компоновалось в один большой файл ядра.
Но скоро стали ясны недостатки такого подхода:
- Для включения в состав ядра новых компонентов надо было пересобирать ядро;
- Незащищенность компонентов ядра друг от друга, т.к. в режиме ядра нет защиты памяти
- Сложность отладки, поскольку каждый компонент мог напрямую менять структуры других компонентов
- Поскольку ядро очень быстро росло в размерах (в основном, из-за драйверов), то вероятность ошибок в коде была очень велика
Поэтому были разработаны монолитные ядра с элементами модульности, что позволило (во время загрузки ОС или во время исполнения) загрузить добавочный кусок кода в режим ядра. Обычно это применялось для загрузки драйверов и файловых систем.
Микроядро
По указанным выше причинам, еще в 80-х годах XX века появилась идея переместить большинство компонентов ОС в пространство пользователя, оставив в ядре только минимальный набор компонентов. Такие минимальные ядра были названы микроядрами.
Преимущества такого подхода:
- Более модульный подход: добавлять компоненты ОС можно без постоянной пересборки одного большого бинарника
- Улучшенная защита компонентов друг от друга, т.к. они разнесены по разным адресным пространствам
- Более простая отладка ввиду изоляции и инкапсуляции ошибок в своем компоненте
- Разные компоненты могут общаться с другими компонентами только через жестко заданные интерфейсы, что также улучшило общую структуру и независимость компонентов друг от друга. Можно произвольно менять внутреннюю структуру компонентов, сохраняя их интерфейсы
Можно заметить, что этот подход согласуется с принципами модульного и объектно-ориентированного программирования
Есть, конечно, недостатки и у микроядерного подхода. Первые микроядра имели заметно меньшую производительность, чем монолитные ядра.
Причины этого состояли в том, что:
- очень многое было завязано на передаче сообщений микроядра, производительность которого оказывалась критичной
- в микроядрах частота изменения контекста и перехода из пользовательского режима в режим ядра была больше
- неэффективность кеширования кода ядра, частые случаи когда кода в кеше на нужный момент нет.
Это определило причины неудач первых микроядер, таких как микроядро Mach, разработанное Университетом Карнеги-Меллона.
В начале 1990-х гг были созданы микроядра 2-го поколения, в которых эти проблемы были решены (эти ядра, первым из которых было микроядро L4? конечно, все еще уступают в производительности монолитным ядрам, но всего на пару процентов). Это было достигнуто при помощи:
- оптимизации передачи сообщений, например, передачей маленьких сообщений внутри регистров процессора, а также передачей строк не копированием, а установкой временной области разделяемой памяти и передачей только ссылки
- смена контекста и переход из/в ядро также были оптимизированы
- микроядро было оптимизировано под каждую целевую архитектуру, так что реализация одних и тех же операций для разных процессоров делалась совершенно различными способами, более подходящими в данной ситуации.
- благодаря реализации принципа "Microkernels must be small", микроядро полностью помещается в L1-кеш процессора, что способствует эффективному кешированию