The design of the unix operating system by Maurice J

Вид материалаРеферат
G6.8 упражненияh
Управление процессом
7.1 Создание процесса
Подобный материал:
1   ...   19   20   21   22   23   24   25   26   ...   55
главах при рассмотрении системных функций управления процессами и

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

тодов распределения памяти.


G6.8 УПРАЖНЕНИЯH


1. Составьте алгоритм преобразования виртуальных адресов в фи-

зические, на входе которого задаются виртуальный адрес и ад-

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

2. В машинах AT&T 3B2 и NSC серии 32000 используется двухуров-

невая схема трансляции виртуальных адресов в физические (с

сегментацией). То есть в системе поддерживается указатель на

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

сированную часть адресного пространства процесса по смещению

в таблице. Сравните алгоритм трансляции виртуальных адресов

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

дении модели управления памятью. Подумайте над проблемами

производительности и потребности в памяти для размещения

вспомогательных таблиц.

3. В архитектуре системы VAX-11 поддерживаются два набора ре-

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

трансляции пользовательских адресов. Механизм трансляции ис-

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

лючением: указателей на таблицу страниц здесь два. Если про-

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

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

производить отображение областей на таблицы страниц ? Увели-

чение стека в архитектуре системы VAX-11 идет в направлении

младших виртуальных адресов. Какой тогда вид имела бы об-

ласть стека ? В главе 11 будет рассмотрена область разделяе-

мой памяти: как она может быть реализована в архитектуре

системы VAX-11 ?

4. Составьте алгоритм выделения и освобождения страниц памяти и

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

чтобы достичь наивысшей производительности или наибольшей

простоты реализации алгоритма ?

5. Устройство управления памятью MC68451 для семейства микро-

процессоров Motorola 68000 допускает выделение сегментов па-

мяти размером от 256 байт до 16 мегабайт. Каждое (физичес-

кое) устройство управления памятью поддерживает 32

дескриптора сегментов. Опишите эффективный метод выделения

памяти для этого случая. Каким образом осуществлялась бы ре-

ализация областей ?

6. Рассмотрим отображение виртуальных адресов, представленное

на Рисунке 6.5. Предположим, что ядро выгружает процесс (в

системе с подкачкой процессов) или откачивает в область сте-

ка большое количество страниц (в системе с замещением стра-

ниц). Если через какое-то время процесс обратится к вирту-

альному адресу 68432, будет ли он должен обратиться к

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

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

(откачки) ? Если нижние уровни системы управления памятью

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

таблицы располагать в тех же, что и сами страницы, местах

физической памяти ?

*7. Можно реализовать систему, в которой стек ядра располагается

над вершиной стека задачи. Подумайте о достоинствах и недос-

татках подобной системы.

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

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

ные адреса областей, уже присоединенных к процессу ?

9. Обратимся к алгоритму переключения контекста. Допустим, что

в системе готов к выполнению только один процесс. Другими

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

сохраненным контекстом. Объясните, что произойдет при этом.

10. Предположим, что процесс приостановился, но в системе нет

процессов, готовых к выполнению. Что произойдет, когда при-

остановившийся процесс переключит контекст ?

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

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

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

процесс. Объясните, почему переключение контекста произойдет

на системном контекстном уровне 2.

12. В системе с замещением страниц процесс, выполняемый в режиме

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

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

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

навливается. Объясните, почему переключение контекста (в

момент приостанова) произойдет на системном контекстном

уровне 2.

13. Процесс использует системную функцию read с форматом вызова

read(fd,buf,1024);

в системе с замещением страниц памяти. Предположим, что ядро

исполняет алгоритм read для считывания данных в системный

буфер, однако при попытке копирования данных в адресное

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

ницы, содержащей структуру buf, вследствие того, что она бы-

ла ранее выгружена из памяти. Ядро обрабатывает возникшее

прерывание, считывая отсутствующую страницу в память. Что

происходит на каждом из системных контекстных уровней ? Что

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

вится в ожидании завершения считывания страницы ?

14. Что произошло бы, если бы во время копирования данных из ад-

ресного пространства задачи в память ядра (Рисунок 6.17) об-

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

*15. При выполнении алгоритмов sleep и wakeup ядро повышает

приоритет работы процессора так, чтобы не допустить прерыва-

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

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

твий ? (Намек: ядро зачастую возобновляет приостановленные

процессы прямо из программ обработки прерываний).

*16. Предположим, что процесс пытается приостановиться до наступ-

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

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

прерывание и программа его обработки пытается возобновить

все процессы, приостановленные до наступления события A. Что

случится с первым процессом ? Не представляет ли эта ситуа-

ция опасность ? Если да, то может ли ядро избежать ее воз-

никновения ?

17. Что произойдет, если ядро запустит алгоритм wakeup для всех

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

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

цесса ?

18. По одному адресу может приостановиться множество процессов,

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

из них - тех, которым будет послан соответствующий сигнал. С

помощью механизма посылки сигналов можно идентифицировать

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

извести в алгоритме wakeup для того, чтобы можно было возоб-

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

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

19. Обращения к алгоритмам sleep и wakeup в системе Multics


имеют следующий синтаксис:

sleep (событие);

wakeup (событие, приоритет);

Таким образом, в алгоритме wakeup возобновляемому процессу

присваивается приоритет. Сравните форму вызова этих алгорит-

мов с формой вызова соответствующих алгоритмов в системе

UNIX.

УПРАВЛЕНИЕ ПРОЦЕССОМ


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

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

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

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

exit завершает выполнение процесса, а wait дает возможность роди-

тельскому процессу синхронизировать свое продолжение с завершени-

ем порожденного процесса. Об асинхронных событиях процессы инфор-

мируются при помощи сигналов. Поскольку ядро синхронизирует

выполнение функций exit и wait при помощи сигналов, описание ме-

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

wait. Системная функция exec дает процессу возможность запускать

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

няемый образ файла. Системная функция brk позволяет динамически

выделять дополнительную память; теми же самыми средствами ядро

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

ти дополнительное пространство. В заключительной части главы да-

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

сора shell и начального процесса init.

На Рисунке 7.1 показана взаимосвязь между системными функция-

ми, рассматриваемыми в данной главе, с одной стороны, и алгорит-

мами, описанными в предыдущей главе, с другой. Почти во всех

функциях используются алгоритмы sleep и wakeup, отсутствующие на

рисунке. Функция exec, кроме того, взаимодействует с алгоритмами

работы с файловой системой, речь о которых шла в главах 4 и 5.


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

│ Системные функции, имеющие │ Системные функции, │ Функции │

│ ющие дело с управлением па- │ связанные с синхро- │ смешанного │

│ мятью │ низацией │ типа │

+-------T-------T-------T-----+--T----T------T----T-+-----T------+

│ fork │ exec │ brk │ exit │wait│signal│kill│setrgrp│setuid│

+-------+-------+-------+--------+----+------+----+-------+------+

│dupreg │detach-│growreg│ detach-│ │

│attach-│ reg │ │ reg │ │

│ reg │alloc- │ │ │ │

│ │ reg │ │ │ │

│ │attach-│ │ │ │

│ │ reg │ │ │ │

│ │growreg│ │ │ │

│ │loadreg│ │ │ │

│ │mapreg │ │ │ │

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


Рисунок 7.1. Системные функции управления процессом и их

связь с другими алгоритмами


7.1 СОЗДАНИЕ ПРОЦЕССА


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

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

fork. Процесс, вызывающий функцию fork, называется родительским

(процесс-родитель), вновь создаваемый процесс называется порож-

денным (процесс-потомок). Синтаксис вызова функции fork:

pid = fork();

В результате выполнения функции fork пользовательский контекст и

того, и другого процессов совпадает во всем, кроме возвращаемого

значения переменной pid. Для родительского процесса в pid возвра-

щается идентификатор порожденного процесса, для порожденного -

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

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

создаваемым с помощью функции fork.

В ходе выполнения функции ядро производит следующую последо-

вательность действий:

1. Отводит место в таблице процессов под новый процесс.

2. Присваивает порождаемому процессу уникальный код идентифика-

ции.

3. Делает логическую копию контекста родительского процесса.

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

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

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

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

область.

4. Увеличивает значения счетчика числа файлов, связанных с про-

цессом, как в таблице файлов, так и в таблице индексов.

5. Возвращает родительскому процессу код идентификации порожден-

ного процесса, а порожденному процессу - нулевое значение.


Реализацию системной функции fork, пожалуй, нельзя назвать

тривиальной, так как порожденный процесс начинает свое выполне-

ние, возникая как бы из воздуха. Алгоритм реализации функции для

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

процессов имеет лишь незначительные различия; все изложенное ниже

в отношении этого алгоритма касается в первую очередь традицион-

ных систем с подкачкой процессов, но с непременным акцентировани-

ем внимания на тех моментах, которые в системах с замещением

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

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

достаточная для размещения порожденного процесса. В главе 9 будет

отдельно рассмотрен случай, когда для порожденного процесса не

хватает памяти, и там же будут даны разъяснения относительно реа-

лизации алгоритма fork в системах с замещением страниц.


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

│ алгоритм fork │

│ входная информация: отсутствует │

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

│ катор (PID) порожденного процесса │

│ для порожденного процесса - 0 │

│ { │

│ проверить доступность ресурсов ядра; │

│ получить свободное место в таблице процессов и уникаль- │

│ ный код идентификации (PID); │

│ проверить, не запустил ли пользователь слишком много │

│ процессов; │

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

│ в состоянии "создания"; │

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

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

│ ветствующую порожденному процессу; │

│ увеличить значения счетчиков ссылок на текущий каталог и│

│ на корневой каталог (если он был изменен); │

│ увеличить значение счетчика открытий файла в таблице │

│ файлов; │

│ сделать копию контекста родительского процесса (адресное│

│ пространство, команды, данные, стек) в памяти; │

│ поместить в стек фиктивный уровень системного контекста │

│ над уровнем системного контекста, соответствующим по- │

│ рожденному процессу; │

│ фиктивный контекстный уровень содержит информацию, │

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

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

│ запускаться с этого места; │

│ если (в данный момент выполняется родительский процесс) │

│ { │

│ перевести порожденный процесс в состояние "готовности│

│ к выполнению"; │

│ возвратить (идентификатор порожденного процесса); │

│ /* из системы пользователю */ │

│ } │

│ в противном случае /* выполняется порожденный │

│ процесс */ │

│ { │

│ записать начальные значения в поля синхронизации ад- │

│ ресного пространства процесса; │

│ возвратить (0); /* пользователю */ │

│ } │

│ } │

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


Рисунок 7.2. Алгоритм fork


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

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

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

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

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

следует выделить память для вспомогательных таблиц (в частности,

таблиц страниц). Если свободных ресурсов нет, алгоритм fork за-

вершается неудачно. Ядро ищет место в таблице процессов для конс-

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

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

мально-допустимое количество параллельно запущенных процессов.

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

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

ществующих идентификаторов. Если предлагаемый идентификатор уже

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

порядку. Как только будет достигнуто максимально-допустимое зна-

чение, отсчет идентификаторов опять начнется с 0. Поскольку боль-

шинство процессов имеет короткое время жизни, при переходе к на-

чалу отсчета значительная часть идентификаторов оказывается сво-

бодной.

На количество одновременно выполняющихся процессов

накладывается ограничение (конфигурируемое), отсюда ни один из

пользователей не может занимать в таблице процессов слишком много

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

цессы. Кроме того, простым пользователям не разрешается создавать

процесс, занимающий последнее свободное место в таблице процес-

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

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

не может гарантировать, что все существующие процессы завершатся

естественным образом, поэтому новые процессы создаваться не бу-

дут. С другой стороны, суперпользователю нужно дать возможность

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

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

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

место. Предполагается, что суперпользователь может прибегать к

решительным мерам и запускать процесс, побуждающий остальные про-

цессы к завершению, если это вызывается необходимостью (см. раз-

дел 7.2.3, где говорится о системной функции kill).

Затем ядро присваивает начальные значения различным полям за-

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

копируя в них значения полей из записи родительского процесса.

Например, порожденный процесс "наследует" у родительского процес-

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

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

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

функции nice и используемое при вычислении приоритета планирова-

ния. В следующих разделах мы поговорим о назначении этих полей.

Ядро передает значение поля идентификатора родительского процесса

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

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

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

сурсов центрального процессора и другие значения полей синхрони-

зации. Начальным состоянием процесса является состояние "созда-

ния" (см. Рисунок 6.1).

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

файлы, с которыми автоматически связывается порождаемый процесс.

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

дительского процесса. Число процессов, обращающихся в данный мо-

мент к каталогу, увеличивается на 1 и, соответственно, увеличива-

ется значение счетчика ссылок на его индекс. Во-вторых, если

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

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

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

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

лицу пользовательских дескрипторов для родительского процесса в

поисках открытых файлов, известных процессу, и увеличивает значе-

ние счетчика ссылок, ассоциированного с каждым из открытых фай-

лов, в глобальной таблице файлов. Порожденный процесс не просто

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

к файлам с родительским процессом, так как оба процесса обращают-

ся в таблице файлов к одним и тем же записям. Действие fork в от-

ношении открытых файлов подобно действию алгоритма dup: новая за-

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

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

файлу. Для dup, однако, записи в таблице пользовательских деск-

рипторов файла относятся к одному процессу; для fork - к разным

процессам.