The design of the unix operating system by Maurice J

Вид материалаРеферат
Подобный материал:
1   2   3   4   5   6   7   8   9   ...   55


Обычные файлы и каталоги хранятся в системе UNIX на устройс-

твах ввода-вывода блоками, таких как магнитные ленты или диски.

Поскольку существует некоторое различие во времени доступа к этим

устройствам, при установке системы UNIX на лентах размещают фай-

ловые системы. С годами бездисковые автоматизированные рабочие

места станут общим случаем, и файлы будут располагаться в удален-

ной системе, доступ к которой будет осуществляться через сеть

(см. главу 13). Для простоты, тем не менее, в последующем тексте

подразумевается использование дисков. В системе может быть нес-

колько физических дисков, на каждом из которых может размещаться

одна и более файловых систем. Разбивка диска на несколько файло-

вых систем облегчает администратору управление хранимыми данными.

На логическом уровне ядро имеет дело с файловыми системами, а не

с дисками, при этом каждая система трактуется как логическое уст-

ройство, идентифицируемое номером. Преобразование адресов логи-

ческого устройства (файловой системы) в адреса физического уст-

ройства (диска) и обратно выполняется дисковым драйвером. Термин

"устройство" в этой книге используется для обозначения логическо-

го устройства, кроме специально оговоренных случаев.

Файловая система состоит из последовательности логических

блоков длиной 512, 1024, 2048 или другого числа байт, кратного

512, в зависимости от реализации системы. Размер логического бло-

ка внутри одной файловой системы постоянен, но может варьировать-

ся в разных файловых системах в данной конфигурации. Использова-

ние логических блоков большого размера увеличивает скорость пере-

дачи данных между диском и памятью, поскольку ядро сможет

передать больше информации за одну дисковую операцию, и сокращает


количество продолжительных операций. Например, чтение 1 Кбайта с

диска за одну операцию осуществляется быстрее, чем чтение 512

байт за две. Однако, если размер логического блока слишком велик,

полезный объем памяти может уменьшиться, это будет показано в

главе 5. Для простоты термин "блок" в этой книге будет использо-

ваться для обозначения логического блока, при этом подразумевает-

ся логический блок размером 1 Кбайт, кроме специально оговоренных

случаев.


----------T---------T---------------T-------------┐

│ │ │ │ │

L---------+---------+---------------+--------------

блок супер- список индексов информационные

загрузки блок блоки


Рисунок 2.3. Формат файловой системы


Файловая система имеет следующую структуру (Рисунок 2.3).


* Блок загрузки располагается в начале пространства, отведенного

под файловую систему, обычно в первом секторе, и содержит прог-

рамму начальной загрузки, которая считывается в машину при заг-

рузке или инициализации операционной системы. Хотя для запуска

системы требуется только один блок загрузки, каждая файловая

система имеет свой (пусть даже пустой) блок загрузки.

* Суперблок описывает состояние файловой системы - какого она

размера, сколько файлов может в ней храниться, где располагает-

ся свободное пространство, доступное для файловой системы, и

другая информация.

* Список индексов в файловой системе располагается вслед за су-

перблоком. Администраторы указывают размер списка индексов при

генерации файловой системы. Ядро операционной системы обращает-

ся к индексам, используя указатели в списке индексов. Один из

индексов является корневым индексом файловой системы: это ин-

декс, по которому осуществляется доступ к структуре каталогов

файловой системы после выполнения системной операции mount

(монтировать) (раздел 5.14).

* Информационные блоки располагаются сразу после списка индексов

и содержат данные файлов и управляющие данные. Отдельно взятый

информационный блок может принадлежать одному и только одному

файлу в файловой системе.


2.2.2 Процессы


В этом разделе мы рассмотрим более подробно подсистему управ-

ления процессами. Даются разъяснения по поводу структуры процесса

и некоторых информационных структур, используемых при распределе-

нии памяти под процессы. Затем дается предварительный обзор диаг-

раммы состояния процессов и затрагиваются различные вопросы, свя-

занные с переходами из одного состояния в другое.

Процессом называется последовательность операций при

выполнении программы, которые представляют собой наборы байтов,

интерпретируемые центральным процессором как машинные инструкции

(т.н. "текст"), данные и стековые структуры. Создается впечатле-

ние, что одновременно выполняется множество процессов, поскольку

их выполнение планируется ядром, и, кроме того, несколько процес-

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

заключается в точном следовании набору инструкций, который явля-

ется замкнутым и не передает управление набору инструкций другого

процесса; он считывает и записывает информацию в раздел данных и

в стек, но ему недоступны данные и стеки других процессов. Одни

процессы взаимодействуют с другими процессами и с остальным миром

посредством обращений к операционной системе.

С практической точки зрения процесс в системе UNIX является

объектом, создаваемым в результате выполнения системной операции

fork. Каждый процесс, за исключением нулевого, порождается в ре-

зультате запуска другим процессом операции fork. Процесс, запус-

тивший операцию fork, называется родительским, а вновь созданный

процесс - порожденным. Каждый процесс имеет одного родителя, но

может породить много процессов. Ядро системы идентифицирует каж-

дый процесс по его номеру, который называется идентификатором

процесса (PID). Нулевой процесс является особенным процессом, ко-

торый создается "вручную" в результате загрузки системы; после

порождения нового процесса (процесс 1) нулевой процесс становится

процессом подкачки. Процесс 1, известный под именем init, являет-

ся предком любого другого процесса в системе и связан с каждым

процессом особым образом, описываемым в главе 7.

Пользователь, транслируя исходный текст программы, создает

исполняемый файл, который состоит из нескольких частей:

* набора "заголовков", описывающих атрибуты файла,

* текста программы,

* представления на машинном языке данных, имеющих начальные

значения при запуске программы на выполнение, и указания на то,

сколько пространства памяти ядро системы выделит под неинациали-

зированные данные, так называемые bss (*) (ядро устанавливает их

в 0 в момент запуска),

* других секций, таких как информация символических таблиц.

Для программы, приведенной на Рисунке 1.3, текст исполняемого

файла представляет собой сгенерированный код для функций main и

copy, к определенным данным относится переменная version (встав-

ленная в программу для того, чтобы в последней имелись некоторые

определенные данные), а к неопределенным - массив buffer. Компи-

лятор с языка Си для системы версии V создает отдельно текстовую

секцию по умолчанию, но не исключается возможность включения инс-

трукций программы и в секцию данных, как в предыдущих версиях

системы.

Ядро загружает исполняемый файл в память при выполнении сис-

темной операции exec, при этом загруженный процесс состоит по

меньшей мере из трех частей, так называемых областей: текста,

данных и стека. Области текста и данных корреспондируют с секция-

ми текста и bss-данных исполняемого файла, а область стека созда-

ется автоматически и ее размер динамически устанавливается ядром

системы во время выполнения. Стек состоит из логических записей

активации, помещаемых в стек при вызове функции и выталкиваемых

из стека при возврате управления в вызвавшую процедуру; специаль-

ный регистр, именуемый указателем вершины стека, показывает теку-

щую глубину стека. Запись активации включает параметры передавае-


------------------------------------------------

(*) Сокращение bss имеет происхождение от ассемблерного псевдоо-

ператора для машины IBM 7090 и расшифровывается как "block

started by symbol" ("блок, начинающийся с символа").

мые функции, ее локальные переменные, а также данные, необходимые

для восстановления предыдущей записи активации, в том числе зна-

чения счетчика команд и указателя вершины стека в момент вызова

функции. Текст программы включает последовательности команд, уп-

равляющие увеличением стека, а ядро системы выделяет, если нужно,

место под стек. В программе на Рисунке 1.3 параметры argc и argv,

а также переменные fdold и fdnew, содержащиеся в вызове функции

main, помещаются в стек, как только встретилось обращение к функ-

ции main (один раз в каждой программе, по условию), так же и па-

раметры old и new и переменная count, содержащиеся в вызове функ-

ции copy, помещаются в стек в момент обращения к указанной функ-

ции.

Поскольку процесс в системе UNIX может выполняться в двух ре-

жимах, режиме ядра или режиме задачи, он пользуется в каждом из

этих режимов отдельным стеком. Стек задачи содержит аргументы,

локальные переменные и другую информацию относительно функций,

выполняемых в режиме задачи. Слева на Рисунке 2.4 показан стек

задачи для процесса, связанного с выполнением системной операции

write в программе copy. Процедура запуска процесса (включенная в

библиотеку) обратилась к функции main с передачей ей двух пара-

метров, поместив в стек задачи запись 1; в записи 1 есть место

для двух локальных переменных функции main. Функция main затем

вызывает функцию copy с передачей ей двух параметров, old и new,

и помещает в стек задачи запись 2; в записи 2 есть место для ло-

кальной переменной count. Наконец, процесс активизирует системную

операцию write, вызвав библиотечную функцию с тем же именем. Каж-

дой системной операции соответствует точка входа в библиотеке

системных операций; библиотека системных операций написана на

языке ассемблера и включает специальные команды прерывания, кото-

рые, выполняясь, порождают "прерывание", вызывающее переключение

аппаратуры в режим ядра. Процесс ищет в библиотеке точку входа,

соответствующую отдельной системной операции, подобно тому, как

он вызывает любую из функций, создавая при этом для библиотечной

функции запись активации. Когда процесс выполняет специальную ин-

струкцию, он переключается в режим ядра, выполняет операции ядра

и использует стек ядра.

Стек ядра содержит записи активации для функций, выполняющих-

ся в режиме ядра. Элементы функций и данных в стеке ядра соот-

ветствуют функциям и данным, относящимся к ядру, но не к програм-

ме пользователя, тем не менее, конструкция стека ядра подобна

конструкции стека задачи. Стек ядра для процесса пуст, если про-

цесс выполняется в режиме задачи. Справа на Рисунке 2.4 представ-

лен стек ядра для процесса выполнения системной операции write в

программе copy. Подробно алгоритмы выполнения системной операции

write будут описаны в последующих разделах.


Стек задачи Направление Стек ядра

---------------┐ увеличения стека -------------------┐

│ Локальные │ │ │

│ переменные │ │ │ │

│ (не показаны)│ │ │ . │

│--------------│ │ │ . │

│Адрес записи 2│ │ │ . │

│--------------│ │ │ . │

│Адрес возврата│ │ │ . │

│ после вызова │ │ │ . │

│ write │ │ │ . │

│--------------│ │ │ . │

│параметры, пе-│ │ │ . │

│ редаваемые │ │ │ . │

│ write │ │ │ . │

│(new, buffer, │ │ │ v │

│ count) │ Запись 3 │ │

+--------------+ call write() Запись 3 +------------------+

│ Локальные │ │ Локальные │

│ переменные │ │ переменные │

│ (count) │ │ │

│--------------│ │------------------│

│Адрес записи 1│ │ Адрес записи 1 │

│--------------│ │------------------│

│Адрес возврата│ │ Адрес возврата │

│ после вызова │ │ после вызова │

│ copy │ │ func2 │

│--------------│ │------------------│

│параметры, пе-│ │ параметры, пере- │

│ редаваемые │ │ даваемые функции │

│ copy │ │ ядра func2 │

│ (old, new) │ Запись 2 Запись 2 │ │

+--------------+ call copy() call func2() +------------------+

│ Локальные │ │ Локальные │

│ переменные │ │ переменные │

│(fdold, fdnew)│ │ │

│--------------│ │------------------│

│Адрес записи 0│ │ Адрес записи 0 │

│--------------│ │------------------│

│Адрес возврата│ │ Адрес возврата │

│ после вызова │ │ после вызова │

│ main │ │ func1 │

│--------------│ │------------------│

│параметры, пе-│ │ параметры, пере- │

│ редаваемые │ │ даваемые функции │

│ main │ │ ядра func1 │

│ (argc, argv) │ Запись 1 Запись 1 │ │

L--------------- call main() call func1() L-------------------


Запись 0 Запись 0

Старт Интерфейс

обращений к

операционной

системе


Рисунок 2.4. Стеки задачи и ядра для программы копирования.


промежуточная

таблица облас- таблица

тей процессов областей

----------------------┐ --------------┐ -------------┐

│ часть адресного про-│ │ │ │ │

│ странства задачи, │ │ │ │ │

│ выделенная процессу │ │ │ │ │

L---------------------- +-------------+ +------------+

---+-> ---+-----+-> │

│ │ +-------------+ +-----+------+

-----------+----------┐ +--+-> ---+--┐ │ │ │

│ │ │ │ +-------------+ │ │ │ │

│ │ │ │ │ │ │ │ │ │

│ │ │ │ │ │ │ +-----+------+

+----------+----------+ │ │ │ L--+-> │ │

│ v -----+--- │ │ +-----+---+--+

+---------------------+ │ │ │ │ │ │

│ │ │ │ │ │ │ │

│ │ L-------------- L-----+---+---

│ │ │ │

L---------------------- │ │

таблица процессов --------------------------+---+--┐

│ оперативная память v v │

L---------------------------------


Рисунок 2.5. Информационные структуры для процессов


Каждому процессу соответствует точка входа в таблице процес-

сов ядра, кроме того, каждому процессу выделяется часть оператив-

ной памяти, отведенная под задачу пользователя. Таблица процессов

включает в себя указатели на промежуточную таблицу областей про-

цессов, точки входа в которую служат в качестве указателей на

собственно таблицу областей. Областью называется непрерывная зона

адресного пространства, выделяемая процессу для размещения текс-


та, данных и стека. Точки входа в таблицу областей описывают ат-

рибуты области, как например, хранятся ли в области текст прог-

раммы или данные, закрытая ли эта область или же совместно ис-

пользуемая, и где конкретно в памяти размещается содержимое об-

ласти. Внешний уровень косвенной адресации (через промежуточную

таблицу областей, используемых процессами, к собственно таблице

областей) позволяет независимым процессам совместно использовать

области. Когда процесс запускает системную операцию exec, ядро

системы выделяет области под ее текст, данные и стек, освобождая

старые области, которые использовались процессом. Если процесс

запускает операцию fork, ядро удваивает размер адресного прост-

ранства старого процесса, позволяя процессам совместно использо-

вать области, когда это возможно, и, с другой стороны, производя

физическое копирование. Если процесс запускает операцию exit, яд-

ро освобождает области, которые использовались процессом. На Ри-

сунке 2.5 изображены информационные структуры, связанные с запус-

ком процесса. Таблица процессов ссылается на промежуточную

таблицу областей, используемых процессом, в которой содержатся

указатели на записи в собственно таблице областей, соответствую-

щие областям для текста, данных и стека процесса.

Запись в таблице процессов и часть адресного пространства за-

дачи, выделенная процессу, содержат управляющую информацию и дан-

ные о состоянии процесса. Это адресное пространство является

расширением соответствующей записи в таблице процессов, различия

между данными объектами будут рассмотрены в главе 6. В качестве

полей в таблице процессов, которые рассматриваются в последующих

разделах, выступают:

* поле состояния,

* идентификаторы, которые характеризуют пользователя, являю-

щегося владельцем процесса (код пользователя или UID),

* значение дескриптора события, когда процесс приостановлен

(находится в состоянии "сна").

Адресное пространство задачи, выделенное процессу, содержит

описывающую процесс информацию, доступ к которой должен обеспечи-

ваться только во время выполнения процесса. Важными полями явля-

ются:

* указатель на позицию в таблице процессов, соответствующую

текущему процессу,

* параметры текущей системной операции, возвращаемые значения

и коды ошибок,

* дескрипторы файла для всех открытых файлов,

* внутренние параметры ввода-вывода,

* текущий каталог и текущий корень (см. главу 5),

* границы файлов и процесса.

Ядро системы имеет непосредственный доступ к полям адресного

пространства задачи, выделенного выполняемому процессу, но не

имеет доступ к соответствующим полям других процессов. С точки

зрения внутреннего алгоритма, при обращении к адресному прост-

ранству задачи, выделенному выполняемому процессу, ядро ссылается

на структурную переменную u, и, когда запускается на выполнение

другой процесс, ядро перенастраивает виртуальные адреса таким об-

разом, чтобы структурная переменная u указывала бы на адресное

пространство задачи для нового процесса. В системной реализации

предусмотрено облегчение идентификации текущего процесса благода-

ря наличию указателя на соответствующую запись в таблице процес-

сов из адресного пространства задачи.


2.2.2.1 Контекст процесса


Контекстом процесса является его состояние, определяемое

текстом, значениями глобальных переменных пользователя и информа-

ционными структурами, значениями используемых машинных регистров,

значениями, хранимыми в позиции таблицы процессов и в адресном

пространстве задачи, а также содержимым стеков задачи и ядра, от-

носящихся к данному процессу. Текст операций системы и ее гло-

бальные информационные структуры совместно используются всеми

процессами, но не являются составной частью контекста процесса.

Говорят, что при запуске процесса система исполняется в кон-

тексте процесса. Когда ядро системы решает запустить другой про-

цесс, оно выполняет переключение контекста с тем, чтобы система

исполнялась в контексте другого процесса. Ядро осуществляет пе-

реключение контекста только при определенных условиях, что мы

увидим в дальнейшем. Выполняя переключение контекста, ядро сохра-

няет информацию, достаточную для того, чтобы позднее переключить-

ся вновь на первый процесс и возобновить его выполнение. Анало-

гичным образом, при переходе из режима задачи в режим ядра, ядро

системы сохраняет информацию, достаточную для того, чтобы позднее

вернуться в режим задачи и продолжить выполнение с прерванного

места. Однако, переход из режима задачи в режим ядра является

сменой режима, но не переключением контекста. Если обратиться еще

раз к Рисунку 1.5, можно сказать, что ядро выполняет переключение

контекста, когда меняет контекст процесса A на контекст процесса

B; оно меняет режим выполнения с режима задачи на режим ядра и