ПРИМЕЧАНИЕ
Подробности о работе ядра вы можете узнать из книг Operating System Concepts («Основные принципы операционных систем»), 9-е издание, авторы: Авраам Зильбершатц (Abraham Silberschatz), Питер Б. Гелвин (Peter B. Galvin) и Грег Гэнн (Greg Gagne) (Wiley, 2012) и Modern Operating Systems («Современные операционные системы»), 4-е издание, авторы: Эндрю С. Таненбаум (Andrew S. Tanenbaum) и Герберт Бос (Herbert Bos) (Prentice Hall, 2014).
1.3.1. Управление процессами
В любой современной операционной системе несколько процессов функционируют «одновременно». Например, в одно и то же время вы можете запустить на компьютере браузер и открыть электронную таблицу. Тем не менее на самом деле все обстоит не так, как выглядит: процессы, которые отвечают за эти приложения, как правило, не запускаются
Рассмотрим систему с одним центральным процессором. Его могут использовать несколько процессов, но в каждый конкретный момент времени только один процесс может в действительности применять процессор. На практике каждый процесс использует процессор в течение малой доли секунды, а затем приостанавливается; после этого другой процесс применяет процессор в течение малой доли секунды; далее наступает черед третьего процесса и т. д. Действие, при котором какой-либо процесс передает другому процессу управление процессором, называется
Каждый отрезок времени —
Ядро отвечает за переключение контекста. Чтобы понять, как это работает, представим ситуацию, в которой процесс запущен в режиме пользователя, но его квант времени заканчивается. Вот что при этом происходит.
1. Процессор (реальное аппаратное средство) прерывает текущий процесс, опираясь на внутренний таймер, переключается в режим ядра и возвращает ему управление.
2. Ядро записывает текущее состояние процессора и памяти, которые будут необходимы для возобновления только что прерванного процесса.
3. Ядро выполняет любые задачи, которые могли появиться в течение предыдущего кванта времени (например, сбор данных или операции ввода/вывода).
4. Теперь ядро готово к запуску другого процесса. Оно анализирует список процессов, готовых к запуску, и выбирает какой-либо из них.
5. Ядро готовит память для нового процесса, а затем подготавливает процессор.
6. Ядро сообщает процессору, сколько будет длиться квант времени для нового процесса.
7. Ядро переводит процессор в режим пользователя и передает процессору управление.
Переключение контекста дает ответ на важный вопрос:
В системе с несколькими процессорами дело обстоит немного сложнее, поскольку ядру нет необходимости прекращать управление текущим процессором, чтобы позволить запуск какого-либо процесса на другом процессоре. И тем не менее, чтобы извлечь максимальную пользу из всех доступных процессоров, ядро все же так поступает (и может применить определенные хитрости, чтобы получить дополнительное процессорное время).
1.3.2. Управление памятью
Поскольку ядро должно управлять памятью во время переключения контекста, оно наделено этой сложной функцией. Работа ядра сложна, поскольку необходимо учитывать следующие условия:
• ядро должно располагать собственной областью памяти, к которой не могут получить доступ пользовательские процессы;
• каждому пользовательскому процессу необходима своя область памяти;
• какой-либо пользовательский процесс не должен иметь доступ к области памяти, предназначенной для другого процесса;
• пользовательские процессы могут совместно использовать память;
• некоторые участки памяти для пользовательских процессов могут быть предназначены только для чтения;
• система может применять больше памяти, чем ее есть в наличии, задействовав в качестве вспомогательного устройства дисковое пространство.
У ядра есть помощник. Современные процессоры содержат
Примечание
Реализация карты адресов памяти называется таблицей страниц.
О том, как отслеживать производительность памяти, вы узнаете из главы 8.
1.3.3. Драйверы устройств и управление ими
Задача ядра по отношению к устройствам довольно проста. Как правило, устройства доступны только в режиме ядра, поскольку некорректный доступ (например, когда пользовательский процесс пытается выключить питание) может вызвать отказ в работе компьютера. Еще одна проблема заключается в том, что различные устройства редко обладают одинаковым программным интерфейсом, даже если они выполняют одинаковую задачу: например, две различные сетевые карты. По этой причине драйверы устройств традиционно являются частью ядра и стремятся предоставить унифицированный интерфейс для пользовательских процессов, чтобы облегчить труд разработчиков программного обеспечения.
1.3.4. Системные вызовы и поддержка
Существуют и другие типы функций ядра, доступные для пользовательских процессов. Например,
Два системных вызова — fork() и exec() — важны для понимания того, как происходит запуск процессов:
• fork(). Когда процесс осуществляет вызов fork(), ядро создает практически идентичную копию данного процесса;
• exec(). Когда процесс осуществляет вызов exec(
За исключением процесса init (глава 6),
Рис. 1.2. Запуск нового процесса
ПРИМЕЧАНИЕ
Системные вызовы обычно обозначаются с помощью круглых скобок. В примере, показанном на рис. 1.2, процесс, который запрашивает ядро о создании другого процесса, должен осуществить системный вызов fork(). Такое обозначение происходит от способа написания вызовов в языке программирования C. Чтобы понять эту книгу, вам не обязательно знать язык C. Помните лишь о том, что системный вызов — это взаимодействие между процессом и ядром. Более того, в этой книге упрощены некоторые группы системных вызовов. Например, вызов exec() обозначает целое семейство системных вызовов, выполняющих сходную задачу, но отличающихся программной реализацией.
Ядро также поддерживает пользовательские процессы, функции которых отличаются от традиционных системных вызовов. Самыми известными из них являются
примечание
Технически пользовательский процесс, который получает доступ к псевдоустройству, все же вынужден осуществлять системный вызов для открытия этого устройства. Таким образом, процессы не могут полностью обойтись без системных вызовов.
1.4. Пространство пользователя
Область оперативной памяти, которую ядро отводит для пользовательских процессов, называется
Большинство реальных действий системы Linux происходит в пространстве пользователя. Несмотря на то что все процессы с точки зрения ядра являются одинаковыми, они выполняют различные задачи для пользователей. Системные компоненты, которые представляют пользовательские процессы, организованы в виде элементарной структуры — сервисного уровня (или слоя). На рис. 1.3 показан примерный набор компонентов, связанных между собой и взаимодействующих с системой Linux. Простые службы расположены на нижнем уровне (ближе всего к ядру), сервисные программы находятся в середине, а приложения, с которыми работает пользователь, расположены вверху. Рисунок 1.3 является крайне упрощенной схемой, поскольку показаны только шесть компонентов, но вы можете заметить, что верхние компоненты находятся ближе всего к пользователю (пользовательский интерфейс и браузер); компоненты среднего уровня располагают почтовым сервером, который использует браузер; в нижней части присутствует несколько малых компонентов.
Нижний уровень состоит, как правило, из малых компонентов, выполняющих простые задачи. Средний уровень содержит более крупные компоненты, такие как почтовая служба, сервер печати и база данных. Компоненты верхнего уровня выполняют сложные задачи, которые зачастую непосредственно контролирует пользователь. Если один компонент желает воспользоваться другим, то этот второй компонент находится либо на том же сервисном уровне, либо ниже.
Рисунок 1.3 только приблизительно отображает устройство пространства пользователя. В действительности в пространстве пользователя нет правил. Например, большинство приложений и служб записывают диагностические сообщения, которые называются
Рис. 1.3. Типы процессов и взаимодействий
Кроме того, некоторые компоненты пространства пользователя бывает трудно отнести к какой-либо категории. Серверные компоненты, например веб-сервер или сервер базы данных, можно рассматривать как приложения очень высокого уровня, поскольку они выполняют довольно сложные задачи. Такие приложения можно поместить в верхней части рис. 1.3. В то же время пользовательские приложения могут зависеть от серверных, когда необходимо выполнять задачи, с которыми они не могут справиться самостоятельно. В таком случае серверные компоненты следовало бы поместить на средний уровень.
1.5. Пользователи
Ядро системы Linux поддерживает традиционную концепцию пользователя системы Unix.
Пользователи существуют главным образом для того, чтобы соблюдались права доступа и ограничения. У каждого процесса из пространства пользователя существует пользователь-
В системе Linux обычно присутствуют дополнительные пользователи помимо тех, которые соответствуют реальным людям, работающим в системе. Более подробно об этом рассказывается в главе 3, но самым важным пользователем является root. Этот пользователь — исключение из приведенных выше правил, поскольку он может прерывать и изменять ход процессов другого пользователя, а также выполнять чтение любого локального файла. По этой причине пользователь root известен как superuser. О человеке, который может работать как пользователь root, говорят, что у него есть
примечание
Работать с правами root может оказаться опасно. Будет сложно выявить и исправить ошибки, поскольку система позволит вам выполнить что угодно, даже если вы пытаетесь причинить ей вред. Системщики постоянно стараются сделать так, чтобы root-доступ не был необходим, насколько это возможно. Например, при переключении между сетями беспроводного доступа на ноутбуке. В то же время, каким бы могущественным ни был пользователь root, он все-таки работает в режиме пользователя системы, а не в режиме ядра.
1.6. Заглядывая вперед
Итак, вы увидели, из чего состоит работающая система Linux. Пользовательские процессы создают среду, с которой вы непосредственно взаимодействуете. Ядро управляет процессами и аппаратными средствами. Обе эти составляющие — ядро и процессы — располагаются в памяти.
Теоретическая информация — это замечательно, но вы не сможете изучить детали системы Linux, только читая о ней. В следующей главе вы начнете свое путешествие, освоив некоторые основы пространства пользователя. Попутно вы узнаете о более обширных частях системы Linux, о которых не говорилось в этой главе: о долговременных запоминающих устройствах (жестких дисках, файлах и т. п.). Вам ведь необходимо где-то хранить свои программы и данные.
2. Основные команды и структура каталогов
Эта глава является справочником по командам и утилитам операционной системы Unix. Вероятно, вы уже знаете большинство этих команд, но для подкрепления уверенности, в особенности в том, что касается структуры каталогов (см. раздел 2.19), прочитайте данную главу до конца. Здесь представлен вводный материал, на который я буду ссылаться на протяжении всей книги.
Почему речь пойдет о командах Unix? Разве эта книга не о том, как работает Linux? Да, конечно же, об этом, но в самой сердцевине Linux заложена система Unix.
В этой главе вы встретите слово Unix чаще, чем слово Linux, поскольку полученные сведения можно тут же применить к Solaris, BSD и к другим системам, связанным с Unix. Я попытался уйти от рассмотрения излишнего числа расширений пользовательского интерфейса, специфичных для Linux, не только ради того, чтобы у вас появился прочный фундамент для использования других систем, но и потому, что такие расширения довольно нестабильны. Вы сможете адаптировать новые выпуски системы Linux быстрее, если будете знать основные команды.
примечание
Дополнительные подробности для начинающих изучать Linux можно найти в книгах The Linux Command Line («Командная строка Linux») (No Starch Press, 2012), UNIX for the Impatient («UNIX для нетерпеливых») (Addison-Wesley Professional, 1995) и Learning the UNIX Operating System («Осваиваем операционную систему UNIX»), 5-е издание (O’Reilly, 2001).
2.1. Оболочка Bourne shelname = "note" /bin/sh
Оболочка является одной из важнейших частей системы Unix.
Многие важные части системы в действительности являются
По мере чтения этой книги и приобретения практических навыков вы пополните свои знания командами, использующими оболочку. Одно из свойств оболочки позволяет, если вы совершили ошибку, сразу же увидеть, что именно набрано неверно, и попробовать заново.
Существуют различные варианты оболочки Unix, но все они заимствуют некоторые функции от оболочки Bourne shell (/bin/sh) — стандартной оболочки, разработанной в компании Bell Labs для ранних версий системы Unix.
Каждой системе Unix для правильной работы необходимо наличие оболочки Bourne shell. Система Linux использует улучшенную версию оболочки Bourne shell — bash, или «заново рожденную»1 оболочку. Оболочка bash является оболочкой по умолчанию в большинстве дистрибутивов Linux, а путь /bin/sh, как правило, — ссылка на эту оболочку. При запуске примеров из книги следует применять оболочку bash.
примечание
Возможно, оболочка bash не является установленной у вас по умолчанию, если вы используете эту главу как справочник для учетной записи Unix в организации, где вы не являетесь системным администратором. Можно изменить оболочку с помощью команды chsh или попросить помощи у вашего системного администратора.
2.2. Использование оболочки
При установке системы Linux вы должны создать по крайней мере одну учетную запись обычного пользователя (в дополнение к корневому пользователю), которая будет вашей личной учетной записью. В этой главе необходимо входить в систему с учетной записью обычного пользователя.
2.2.1. Окно оболочки
После входа в систему откройте окно оболочки, которое часто называют
В этой книге много команд следует набирать в строке приглашения оболочки. Чтобы обозначить приглашение, все они начинаются с символа $. Наберите приведенную ниже команду (только выделенный жирным шрифтом текст, без символа $) и нажмите клавишу Enter:
$ echo Hello there.