Что необходимо для ОС?
Благо, наряду с двумя перечисленными точками зрения существует и третья. Формулировки ее в явном виде мне не встречалось (хотя в виде неявном, то есть на практике, ее придерживаются разработчики систем BSD-клана). И потому возьму на себя смелость такую формулировку дать: операционная система - это ядро и самодостаточный комплекс средств, необходимых для его функционирования на благо пользователя. То есть пользователь любой ОС, загрузив оную, должен иметь возможность в первую очередь устанавливать, не обращаясь ни к каким сторонним инструментам, необходимое ему программное обеспечение, запускать его и работать с ним. А теперь попробую дать развернутое обоснование третьей позиции.
То, что любая ОС не способна функционировать без ядра - очевидно. Ядро, как и следует из названия, являет собой сердце любой операционной системы, отвечающее за взаимодействие пользовательских приложений (в данном случае - в самом широком смысле слова, включая средства администрирования) с аппаратурой компьютера. Однако с точки зрения пользователя это - (почти) обычный исполняемый бинарный файл, функциональность которого определяется при конфигурировании, предшествующем сборке.
В функции ядра большинства POSIX-систем входят: распределение процессорного времени между задачами, управление памятью - как физической, так и виртуальной (то есть процессом своппинга), взаимодействие с устройствами, доступ к файловым системам, обеспечение ввода/вывода данных, сетевая поддержка.
От всех остальных программ ядро отличается двумя важными особенностями. Во-первых, оно функционирует в отдельной области памяти, которая так и называется пространством ядра (kernelland). И в которую пользовательские процессы доступа не имеют - обращаться, скажем, к устройствам ввода/вывода они должны посредством процедуры системных вызовов к соответствующим подсистемам ядра. Все прочие же программы располагаются в так называемом пользовательском пространстве памяти (userland).
Вторая особенность ядра как исполняемой программы - в том, что, в отличие от всех других программ, оно всегда должно находиться в оперативной памяти физически - то есть не может свопироваться.
Что понятно - ведь если часть ядра, управляющего виртуальной памятью, окажется выгруженной в раздел подкачки, система окажется без средства извлечения ее обратно. Пользовательское пространство остальных программ распределяется между физической оперативной памятью и областью своппинга - в сущности, у пользователя нет ни возможности, ни, скорее всего, необходимости определить, какую из частей единой виртуальной памяти программа использует в данный момент.
Из сказанного следует, что рост функциональности ядра с течением времени неизбежен - для поддержки новых устройств, при сохранении обратной совместимости с устройствами старыми, новых файловых систем, сетевых протоколов, и так далее. Что столь же неизбежно ведет к разрастанию ядра, расходу памяти и падению быстродействия.
Частично эту проблему можно решить индивидуальным конфигурированием ядра, описанным в интермедии . Оно позволяет отключить неиспользуемые в данной системе его функции. Однако как быть с функциями, которые требуются время от времени? А то и вообще только могут потребоваться?
Общее решение этой проблемы было найдено в виде поддержки загружаемых модулей. Это - фрагменты кода, обеспечивающие определенные функции ядра и функционирующие в его пространстве памяти. Но не перманентно, а загружаясь по мере необходимости - вручную, соответствующими командами, или автоматически. И которые могут быть изъяты из памяти, когда в них минует надобность, без перезагрузки системы - до следующего раза.
Соответственно этому, ядра могут быть разделены на монолитные (со встроенной поддержкой всего, чего нужно), и модульные. Впрочем, разделение это - чисто теоретическое: во всех ядрах, в принципе поддерживающих модули (а это - и Linux, и все BSD-системы), они в том или ином объеме используются. Чисто монолитные ядра имеют смысл только для каких-то специальных задач.
Следующий шаг в том же направлении - так называемые микроядра, представителем которых является Mach, время от времени поминаемый в ряде глав этой книги. Их отличие - в том, что "опциональные" фрагменты кода, например, драйверы устройств, не просто вынесены в отдельные модули, но и функционируют в пользовательском пространстве памяти.
А собственно за ядром оставлены функции коммуникаций между ними.
Некогда (вплоть до далекой ныне середины 90-х) микроядра виделись часто как база операционных систем будущего. Однако практические их реализации в большинстве случаев возлагаемых надежд не оправдали: их потенциальные достоинства (например, слабая зависимость от аппаратных платформ) с лихвой перекрывалась недостатками (сложностью взаимодействия компонентов и, как следствием, низким быстродействием). И ныне микроядерная архитектура реализована в узкоспециализированной ОС QNX и в нишевой MacOS X. Однако в последнее время многие идеи, исходящие из проекта Mach, были реализованы в ядре DragonFlyBSD - ответвлении FreeBSD, ориентированном на работу в многопроцессорных системах. Хотя в собственном смысле слова к микроядерным ее отнести нельзя.
Очевидно, что для работы ядро необходимо тем или иным способом загрузить. Что, как будет показано со временем, оно в принципе способно проделать собственными силами - то есть загрузчик не оказывается неотъемлемой частью операционной системы. Однако для функционирования системы недостаточно просто загрузить ядро - необходимо, чтобы оно запустило некий стартовый процесс. В Unix-системах он имеет фиксированное название - init, за запуск которого отвечает одноименный исполняемый файл /sbin/init. Однако в реальных системах под этим именем могут выступать весьма разные программы. И еще - в процессе загрузки следует выполнить некий комплекс мероприятий, определяемый набором сценариев, создающих пользовательское окружение. То есть сочетание инициирующей программы и стартовых скриптов - второй из необходимых составляющих ОС.
Далее следуют утилиты поддержки функций ядра, обеспечивающие работу с устройствами, файловыми системами, сетевыми протоколами. Согласитесь, мало радости пользователю от поддержки ядром некоей файловой системы, если он не располагает инструментами для работы с ней. А отсюда - третий непременный компонент операционки, включающий средства обращения к физическим носителям, создания на них разделов и файловых систем, их проверки, монтирования и т.д.
Если же ядро предусматривает поддержку нескольких файловых систем (как это имеет быть, например, для ядра Linux) в качестве родных (native) - к каждой из них должен прилагаться свой комплекс обслуживающих утилит. При этом следует помнить - многие функции ядра могут быть реализованы как модули, и поэтому средства управления оными - загрузки, выгрузки, получения информации, - также должны быть включены в эту группу.
Все перечисленные выше компоненты - ядро, средства инициализации и системные утилиты, - необходимы для самообеспечения системы. Но ведь цель ее, в конечном счете, - выполнение пользовательских задач. А в основе любой пользовательской задачи лежит манипулирование пользовательскими данными, то есть файлами. И поэтому соответствующий инструментарий - для просмотра файловых систем, манипулирования файлами и их контентом, архивирования и компрессии (то, что можно назвать средствами боевого обеспечения), - оказывается четвертым обязательным компонентом операционной системы. А поскольку файлы пользователя могут располагаться не только на локальной машине, сюда же примыкают и средства сетевого доступа (в том числе и доступа к Интернету).
Для своего функционирования как ядро, так и системные и пользовательские утилиты нуждаются в так называемых системных библиотеках. Из них главной оказывается libc - библиотека функций языка Си (главного средства разработки в контексте Unix-систем). Однако не менее важны и некоторые другие библиотеки, например, например, свойств терминала. Это - своего рода средства тылового обеспечения, практически незаметные пользователю, но, тем не менее, незаменимые. И потому они являют собой пятый обязательный компонент ОС.
Любые действия в любой системе выполняются, прямо или косвенно, путем отдачи соответствующих командных директив. И потому интегрирующей надстройкой над всем описанным богачеством выступает командная оболочка, она же - интерпретатор языка команд, по простому - шелл (shell). Это - шестой компонент ОС, роль которого невозможно переоценить: со временем мы увидим, что и система инициализации - лишь набор сценариев оболочки, и всякого рода приложения с навороченными интерфейсами - лишь надстройки над элементарными шелл-командами и их комбинациями.
И. наконец, последний, седьмой, из необходимых компонентов ОС - внутренняя система документации, дающая пользователю возможность изучения возможностей системы. Таковой испокон веков в Unix выступает система man-страниц (Manual Pages). Не смотря на появление множества других форматов для представления документов, при всей своей архаичности остающаяся простым и универсальным средством оперативного получения исчерпывающей информации.
Таковы предельно минималистские требования к комплектации самодостаточной операционной системы. Именно реализация перечисленных семи компонентов обычно уникальна для каждой ОС и определяет ее своеобразие с точки зрения пользователя. Однако практически их оказывается недостаточно: для полнофункциональной необходимо еще два дополнительных компонента.
Первый - средства наращивания системы дополнительными программами, то есть комплекса инструментов, объединяемых понятием пакетного менеджмента: установки, отслеживания и удовлетворения зависимостей, удаления. Эти действия могут выполняться вручную - посредством простой сборки программ из исходных текстов. И это - универсальный метод, применимый в любой Unix-подобной системе. В этом случае достаточно наличия компилятора для языка Си/Си++ и сопутствующего инструментария (линкера, ассемблера, средств ведения проекта). В свободных POSIX-системах такой инструментарий практически безальтернативен, включая пакеты gcc (компилятор) и binutils с сопутствующими утилитами типа make, automake, autoconfig. Каковые и могут быть включены в операционную систему в качестве восьмого, но уже необязательного, компонента.
Второй метод установки программ - компиляция их из исходников по определенным правилам, освобождающим пользователя от необходимости самому отслеживать и удовлетворять зависимости. В этом случае компилятора и сопутствующего инструментария оказывается недостаточно - требуется еще и система автоматизации сборки. Таковая впервые появилась во FreeBSD под названием системы портов, и в дальнейшем ее аналоги широко распространились как в BSD-мире, так и в многих разновидностях Linux.
Третий метод распространения дополнительных программ - в виде бинарных (прекомпилированных) пакетов. Такие пакеты существуют во множестве различных форматов и, освобождая от необходимости в компиляторе и прочих средствах сборки, требуют для установки специального инструментария - т.н. пакетных менеджеров, обеспечивающего, кроме собственно развертывания пакета, отслеживание и удовлетворение его зависимостей.
И порты, и системы пакетного менеджмента обычно специфичны не только для определенной операционки, но даже отдельных ее разновидностей. В частности, именно пакетными менеджерами различаются между собой различные дистрибутивы Linux. С другой стороны, некоторые системы управления портами и пакетами приобрели широкую популярность за пределами своих родительских операционок и стали фактически кросс-платформенными. И потому их следует относить не к базовым компонентам ОС, а к системам ее распространения (дистрибуции). Тем не менее, подчеркну, что наличие какой-либо системы управления пакетами (хотя бы ручной - в виде компилятора и сопутствующих утилит) абсолютно необходимо для функционирования любой ОС.
И последний из дополнительных (но опять-таки практически необходимых) компинентов ОС - средства для обеспечения работы в графическом режиме. Сам по себе Unix и все его потомки и производные таковых внутри себя не имели и не имеют. Эта функция возлагается на кросс-платформенную систему - X Window System, именуемую также оконной системой X или, в народе, просто Иксами. Изначально не привязанная ни к аппаратной архитектуре, ни к какой-либо ОС, сама по себе она не имеет отношения ни к одному из дистрибутивов Linux, ни к BSD-семейству ОС, ни даже к Unix вообще. Да и стандарты POSIX как-будто бы ничего о ней не говорят - реализации Иксов регламентируются собственными стандартоми, разрабатываемыми специальной организацией - X-консорциумом (X Consorcium).
Тем не менее, Иксы в одной из их свободных реализаций для Intel-совместимых процессоров - XFree86, разрабатываемой в рамках одноименного проекта, или Xorg (составная часть проекта http://freedesktop.org), оказываются непременной частью всех открытых и свободных POSIX-систем - и любого дистрибутива Linux, и всех BSD-клонов.
Иксы заняли свое место в мире Open Sources и Free Software по одной очень важной причине - им фактически нет альтернативы в смысле доступа к графическим возможностям PC. И потому они оказываются практически неотъемлемой частью любой ОС POSIX-семейства - что Linux, что BSD. Они лежат как бы на грани между базовым комплектом этих систем и их обрамлением, выступая по отношению к приложениям графического режима примерно в том же качества, что и базовые компоненты операционки - по отношению к утилитам и приложениям режима текстового. И об этом всегда нужно помнить. Как, впрочем, и о том, что Иксы (в виде ли XFree86, или в реализации Xorg) - это не Linux, не FreeBSD, и не какая-либо другая ОС: это общее достояние всех свободных операционок POSIX-семейства.
И что мы получаем, если соберем вместе все перечисленное выше? А получаем мы практически то, что во FreeBSD охватывается понятием Distributions, вернее, той его частью, которая именуется Base и является единственным компонентом, обязательным при минимальной установке. Аналогичный базовый комплекс программ (так и называемый - Base) есть также в NetBSD и OpenBSD. Причем, если ядра в этих системах и различны, то программы системного обрамления - чрезвычайно близки (местами до полной идентичности).
В Linux'е вычленить нечто подобное из какого-либо многодискового дистрибутива Linux'а несколько сложнее. Однако, напротив, можно прикрутить к его ядру некое подобие такой самодостаточной целостности. По аналогии с BSD ее можно назвать Base Linux. Представление о его составе можно получить, ознакомившись с LFS Book Герарда Бикманса - проектом, посвященным сборке собственной Linux-системы "с нуля".
Подведем итог столь длительных рассуждений. В состав любой POSIX-совместимой системы входит базовый набор из семи обязательных компонентов:
Они дополняются двумя как бы опциональными (на практически столь же обязательными компонентами): той или иной системой управления пакетами и системой поддержки работы в графическом режиме. Весь этот комплекс вполне резонно было бы назвать Base POSIX.