Что такое ядро?

Алексей Федорчук
3 сентября 2008 г

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

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

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

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

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

Третья особенность ядра заключается в том, что оно грузится до того, как становятся доступными все остальные компоненты системы, в частности, библиотечные функции, обеспечивающие его функциональность. Поэтому оно всегда статически линкуется с соответствующими библиотеками — в случае ядра Linux это почти всегда главная системная библиотека функций языка Си, glibc.

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

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

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

Соответственно этому, ядра могут быть разделены на монолитные (со встроенной поддержкой всего, чего нужно), и модульные. Впрочем, разделение это — чисто теоретическое: во всех ядрах, в принципе поддерживающих модули (в их числе и Linux), они в том или ином объеме используются. Чисто монолитные ядра имеют смысл только для каких-то специальных задач. Таким образом, ядро Linux является модульно-монолитным.

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

Ядро Linux — эпонимический компонент этой ОС. Созданное Линусом Торвальдсом в 1991 году, оно на протяжении уже многих лет разрабатывается большим интернациональным коллективом под руководством и при координации основоположника. Команда разработчиков — более или менее неформальное объединение. И теоретически каждый желающий (и, главное, могущий) имеет шанс принять участие в разработке ядра путём посылки своих дополнений (patch). Хотя практически все эти патчи проходят многоступенчатый отбор, прежде чем попасть (или не попасть) к самому Линусу, который и принимает окончательное решение — включать их в официальную версию ядра, или нет.

Официальным своим местопребыванием ядро имеет сайт kernel.org имеющий множество зеркал по всему свету, в том числе и в России. В сущности, исходные тексты ряда версий ядра, их патчей от независимых разработчиков, вместе с некоторыми сопутствующими программами, и составляют единственное содержание этого сайта. С которого их можно получить по Сети — по протоколам HTTP или FTP. Иного способа распространения исходников ядра, насколько мне известно, не существует.

Бытует мнение, что ядро Linux — одно-единственное. Это правда, но не вся правда. Действительно, ядро Линуса — каноническое. Однако практически, кроме текущей его ветки (в настоящее время — 2.6), в которой периодически выходят новые версии (2.6.X) в каждый момент времени развивается и дополняется минимум одна предшествующая ветка (на данный момент 2.4). А одна из еще более старых веток (ныне — 2.2) поддерживается на уровне исправления ошибок. Ошибки, разумеется, имеют место быть и в текущей ветке, где они активно выявляются и исправляются, что образует отдельную «корректирующую» ветку (2.6.xx.y).

Далее, существуют т.н. ядра майнтайнеров (наиболее известные из них — Эндрю Мортон, Алан Кокс, до недавнего времени к ним принадлежал Кон Коливас). Разумеется, в основе всех их — каноническое ядро, но — с патчами, ответственными за реализацию дополнительных функций, не входящих в официальное ядро. Собственно, ядра майнтайнеров и распространяются исключительно в виде патчей к основному дереву исходников ядра. В большинстве случае они доступны на том же kernel.org в каталоге people , где каждый майнтайнер имеет свой подкаталог; однако некоторые патчи приходится искать на сторонних серверах. Со временем большинство патчей майнтайнеров включается в состав официального ядра. Однако эти ребята на достигнутом не останавливаются, и придумывают новые патчи для обеспечения новых возможностей. Так что основные майнтайнерские ветки перманентно существуют параллельно канонической ветке Линуса.

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

Кроме этого, существуют еще и ядра дистрибьюторов — в комплект всех распространенных дистрибутивов, таких, как RHEL, Suse, Mandriva, Ubuntu и так далее, входят заточенные под них ядра собственной выделки (обычно в нескольких вариантах), дополняющие или подменяющие каноническое ядро. Они основаны на патчах майнтайнеров или специализированных проектов, но включают и собственные функции, обеспечивающие оптимальную работу «своего» дистрибутива.

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

Именно различные варианты сборки собственного ядра и составят предмет данного цикла заметок, основанных на опыте их автора и результатах его многочисленных экспериментов.

На протяжении своей работы в Linux’е мне неоднократно приходилось собирать ядра — в разных дистрибутивах и на самом разном железе. Последние упражнения в этой области, послужившие поводом для этого цикла, проводились на машине с процессором Intel Core 2 Duo, материнской платой на чипсете G35 от Intel же с интегрированной графикой и южным мостом ICH9, оперативной памятью 6 Гбайт, двумя винчестерами SATA и CD/DVD приводом с тем же интерфейсом — ни одного PATA-устройства в системе нет. Детали конфигурации описаны ранее — она может рассматриваться как достаточно типичная современная машина на платформе Intel.

Пересборки ядра проводились в дистрибутиве Zenwalk Linux версии 5.2, стандартная редакция, модернизированная до snapshot-ветки по состоянию на 30 августа. Издевательствам подвергались ядра 2.6.26.3 (текущее на момент написания) и 2.6.27-rc5 (самый свежий на данный момент кандидат в релизы). В качестве компилятора был задействован gcc версии 4.2.3.

Добавить комментарий