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

К операциям работы с областями относятся: блокировка области, снятие
блокировки с области, выделение области, присоединение области к пространст-
ву памяти процесса, изменение размера области, загрузка области из файла в
пространство памяти процесса, освобождение области, отсоединение области от
пространства памяти процесса и копирование содержимого области. Например,
системная функция exec, в которой содержимое исполняемого файла накладывает-
ся на адресное пространство задачи, отсоединяет старые области, освобождает
их в том случае, если они не являются разделяемыми, выделяет новые области,
присоединяет их и загружает содержимым файла. В остальной части раздела опе-
рации над областями описываются более детально с ориентацией на модель уп-
равления памятью, рассмотренную ранее (с таблицами страниц и группами аппа-
ратных регистров), и с ориентацией на алгоритмы назначения страниц физичес-
кой памяти и таблиц страниц (глава 9).


    6.5.1 Блокировка области и снятие блокировки



Операции блокировки и снятия блокировки для области выполняются незави-
симо от операций выделения и освобождения области, подобно тому, как опера-
ции блокирования-разблокирования индекса в файловой системе выполняются не-
зависимо от операций назначения-освобождения индекса (алгоритмы iget и
iput). Таким образом, ядро может заблокировать и выделить область, а потом
снять блокировку, не освобождая области. Точно также, когда ядру понадобится
обратиться к выделенной области, оно сможет заблокировать область, чтобы
запретить доступ к ней со стороны других процессов, и позднее снять блоки-
ровку.


    6.5.2 Выделение области



Ядро выделяет новую область (по алгоритму allocreg, Рисунок 6.18) во
время выполнения системных функций fork, exec и shmget (получить разделяемую
память). Ядро поддерживает таблицу областей, записям которой соответствуют
точки входа либо в списке свободных областей, либо в списке активных облас-
тей. При выделении записи в таблице областей ядро выбирает из списка свобод-
ных областей первую доступную запись, включает ее в список активных облас-
тей, блокирует область и делает пометку о ее типе (разделяемая или частная).
За некоторым исключением каждый процесс ассоциируется с исполняемым файлом

160

(после того, как была выполнена команда exec), и в алгоритме allocreg поле
индекса в записи таблицы областей устанавливается таким образом, чтобы оно
указывало на индекс исполняемого файла. Индекс идентифицирует область для
ядра, поэтому другие процессы могут при желании разделять область. Ядро уве-
личивает значение счетчика ссылок на индекс, чтобы помешать другим процессам
удалять содержимое файла при выполнении функции unlink, об этом еще будет
идти речь в разделе 7.5. Результатом алгоритма allocreg является назначение
и блокировка области.

+------------------------------------------------------------+
| алгоритм allocreg /* разместить информационную структуру |
| области */ |
| входная информация: (1) указатель индекса |
| (2) тип области |
| выходная информация: заблокированная область |
| { |
| выбрать область из списка свободных областей; |
| назначить области тип; |
| присвоить значение указателю индекса; |
| если (указатель индекса имеет ненулевое значение) |
| увеличить значение счетчика ссылок на индекс; |
| включить область в список активных областей; |
| возвратить (заблокированную область); |
| } |
+------------------------------------------------------------+

Рисунок 6.18. Алгоритм выделения области



    6.5.3 Присоединение области к процессу



Ядро присоединяет область к адресному пространству процесса во время вы-
полнения системных функций fork, exec и shmat (алгоритм attachreg, Рисунок
6.19). Область может быть вновь назначаемой или уже существующей, которую
процесс будет использовать совместно с другими процессами. Ядро выбирает
свободную запись в частной таблице областей процесса, устанавливает в ней
поле типа таким образом, чтобы оно указывало на область команд, данных, раз-
деляемую память или область стека, и записывает виртуальный адрес, по кото-
рому область будет размещаться в адресном пространстве процесса. Процесс не
должен выходить за предел установленного системой ограничения на максималь-
ный виртуальный адрес, а виртуальные адреса новой области не должны пересе-
каться с адресами существующих уже областей. Например, если система ограни-
чила максимально-допустимое значение виртуального адреса процесса 8 мегабай-
тами, то привязать область размером 1 мегабайт к виртуальному адресу 7.5M не
удастся. Если же присоединение области допустимо, ядро увеличивает значение
поля, описывающего размер области процесса в записи таблицы процессов, на
величину присоединяемой области, а также увеличивает значение счетчика ссы-
лок на область.
Кроме того, в алгоритме attachreg устанавливаются начальные значения
группы регистров управления памятью, выделенных процессу. Если область ранее
не присоединялась к какому-либо процессу, ядро с помощью функции growreg
(см. следующий раздел) заводит для области новые таблицы страниц; в против-
ном случае используются уже существующие таблицы страниц. Алгоритм завершает
работу, возвращая указатель на точку входа в частную таблицу областей про-
цесса, соответствующую вновь присоединенной области. Допустим, например, что
ядру нужно подключить к процессу по виртуальному адресу 0 существующую (раз-
деляемую) область, имеющую размер 7 Кбайт (Рисунок 6.20). Оно выделяет новую


161

+------------------------------------------------------------+
| алгоритм attachreg /* присоединение области к процессу */ |
| входная информация: (1) указатель на присоединяемую об- |
| ласть (заблокированную) |
| (2) процесс, к которому присоединяется|
| область |
| (3) виртуальный адрес внутри процесса,|
| по которому будет присоединена об-|
| ласть |
| (4) тип области |
| выходная информация: точка входа в частную таблицу областей|
| процесса |
| { |
| выделить новую запись в частной таблице областей про- |
| цесса; |
| проинициализировать значения полей записи: |
| установить указатель на присоединяемую область; |
| установить тип области; |
| установить виртуальный адрес области; |
| проверить правильность указания виртуального адреса и |
| размера области; |
| увеличить значение счетчика ссылок на область; |
| увеличить размер процесса с учетом присоединения облас-|
| ти; |
| записать начальные значения в новую группу аппаратных |
| регистров; |
| возвратить (точку входа в частную таблицу областей про-|
| цесса); |
| } |
+------------------------------------------------------------+

Рисунок 6.19. Алгоритм присоединения области


группу регистров управления памятью и заносит в них адрес таблицы страниц
области, виртуальный адрес области в пространстве процесса (0) и размер таб-
лицы страниц (9 записей).


    6.5.4 Изменение размера области



Процесс может расширять или сужать свое виртуальное адресное пространст-
во с помощью функции sbrk. Точно так же и стек процесса расширяется автома-
тически (то есть для этого процессу не нужно явно обращаться к определенной
функции) в соответствии с глубиной вложенности обращений к подпрограммам.
Изменение размера области производится внутри ядра по алгоритму growreg (Ри-
сунок 6.21). При расширении области ядро проверяет, не будут ли виртуальные
адреса расширяемой области пересекаться с адресами какой-нибудь другой об-
ласти и не повлечет ли расширение области за собой выход процесса за пределы
максимально-допустимого виртуального пространства памяти. Ядро никогда не
использует алгоритм growreg для увеличения размера разделяемой области, уже
присоединенной к нескольким процессам; поэтому оно не беспокоится о том, не
приведет ли увеличение размера области для одного процесса к превыше-
нию другим процессом системного ограничения, накладываемого на размер про-
цесса. При работе с существующей областью ядро использует алгоритм growreg в
двух случаях: выполняя функцию sbrk по отношению к области данных процесса и
реализуя автоматическое увеличение стека задачи. Обе эти области (данных и
стека) частного типа. Области команд и разделяемой памяти после инициализа-


162

Частная таблица областей процесса
+---------+-------------+--------+
| Адрес | Виртуальный | Размер |
| таблицы | адрес в про-| и |
| страниц | странстве | защита |
| | процесса | |
+---------+-------------+--------+
Точка входа | | 0 | 9 |
для области +----+----+-------------+--------+
команд +----+
v
+-------------+
| пусто |
+-------------+
| пусто |
+-------------+
| 846K |
+-------------+
| 752K |
+-------------+
| 341K |
+-------------+
| 484K |
+-------------+
| 976K |
+-------------+
| 342K |
+-------------+
| 779K |
+-------------+

Рисунок 6.20. Пример присоединения существующей области команд

ции не могут расширяться. Этот момент будет пояснен в следующей главе.
Чтобы разместить расширенную память, ядро выделяет новые таблицы страниц
(или расширяет существующие) или отводит дополнительную физическую память в
тех системах, где не поддерживается подкачка страниц по обращению. При выде-
лении дополнительной физической памяти ядро проверяет ее наличие перед вы-
полнением алгоритма growreg; если же памяти больше нет, ядро прибегает к
другим средствам увеличения размера области (см. главу 9). Если процесс сок-
ращает размер области, ядро просто освобождает память, отведенную под об-
ласть. Во всех этих случаях ядро переопределяет размеры процесса и области и
переустанавливает значения полей записи частной таблицы областей процесса и
регистров управления памятью (так, чтобы они согласовались с новым отображе-
нием памяти).
Предположим, например, что область стека процесса начинается с виртуаль-
ного адреса 128К и имеет размер 6 Кбайт и что ядру нужно расширить эту об-
ласть на 1 Кбайт (1 страницу). Если размер процесса позволяет это делать и
если виртуальные адреса в диапа-
зоне от 134К до 135К - 1 не принадлежат какой-либо области, ранее присоеди-
ненной к процессу, ядро увеличивает размер стека. При этом ядро расширяет
таблицу страниц, выделяет новую страницу памяти и инициализирует новую за-
пись таблицы. Этот случай проиллюстрирован с помощью Рисунка 6.22.


    6.5.5 Загрузка области



В системе, где поддерживается подкачка страниц по обращению, ядро может


163

+------------------------------------------------------------+
| алгоритм growreg /* изменение размера области */ |
| входная информация: (1) указатель на точку входа в частной|
| таблице областей процесса |
| (2) величина, на которую нужно изме- |
| нить размер области (может быть |
| как положительной, так и отрица- |
| тельной) |
| выходная информация: отсутствует |
| { |
| если (размер области увеличивается) |
| { |
| проверить допустимость нового размера области; |
| выделить вспомогательные таблицы (страниц); |
| если (в системе не поддерживается замещение страниц |
| по обращению) |
| { |
| выделить дополнительную память; |
| проинициализировать при необходимости значения |
| полей в дополнительных таблицах; |
| } |
| } |
| в противном случае /* размер области уменьшается */ |
| { |
| освободить физическую память; |
| освободить вспомогательные таблицы; |
| } |
| |
| провести в случае необходимости инициализацию других |
| вспомогательных таблиц; |
| переустановить значение поля размера в таблице процес- |
| сов; |
| } |
+------------------------------------------------------------+

Рисунок 6.21. Алгоритм изменения размера области


"отображать" файл в адресное пространство процесса во время выполнения функ-
ции exec, подготавливая последующее чтение по запросу отдельных физических
страниц (см. главу 9). Если же подкачка страниц по обращению не поддержива-
ется, ядру приходится копировать исполняемый файл в память, загружая области
процесса по указанным в файле виртуальным адресам. Ядро может присоединить
область к разным виртуальным адресам, по которым будет загружаться содержи-
мое файла, создавая таким образом "разрыв" в таблице страниц (вспомним Рису-
нок 6.20). Эта возможность может пригодиться, например, когда требуется про-
являть ошибку памяти (memory fault) в случае обращения пользовательских
программ к нулевому адресу (если последнее запрещено). Переменные указатели
в программах иногда задаются неверно (отсутствует проверка их значений на
равенство 0) и в результате не могут использоваться в качестве
указателей адресов. Если страницу с нулевым адресом соответствующим образом
защитить, процессы, случайно обратившиеся к этому адресу, натолкнутся на
ошибку и будут аварийно завершены, и это ускорит обнаружение подобных ошибок
в программах.
При загрузке файла в область алгоритм loadreg (Рисунок 6.23) проверяет
разрыв между виртуальным адресом, по которому область присоединяется к про-
цессу, и виртуальным адресом, с которого располагаются данные области, и
расширяет область в соответствии с требуемым объемом памяти. Затем область


164

Частная таблица областей Частная таблица областей
процесса процесса
+-------+----------+------+ +-------+----------+------+
| Адрес | Виртуаль-| Раз- | | Адрес | Виртуаль-| Раз- |
| табли-| ный адрес| мер | | табли-| ный адрес| мер |
| цы | в прост- | и | | цы | в прост- | и |
| стра- | ранстве | защи-| | стра- | ранстве | защи-|
| ниц | процесса | та | | ниц | процесса | та |
+-------+----------+------+ +-------+----------+------+
| | | | | | | |
+-------+----------+------+ +-------+----------+------+
| | | | | | | |
Точка+-------+----------+------+ Точка+-------+----------+------+
входа| | 128K | 6K | входа| | 128K | 7K |
для +---+---+----------+------+ для +---+---+----------+------+
стека +--+ стека +--+
v v
+-------------+ +-------------+
| 342K | | 342K |
+-------------+ +-------------+
| 779K | | 779K |
+-------------+ +-------------+
| 846K | | 846K |
+-------------+ +-------------+
| 752K | | 752K |
+-------------+ +-------------+
| 341K | | 341K |
+-------------+ +-------------+
| 484K | | 484K |
+-------------+ НОВАЯ +-------------+
| | СТРАНИЦА-->| 976K |
+-------------+ +-------------+
| | | |
+-------------+ +-------------+
| | | |
+-------------+ +-------------+
До увеличения стека После увеличения стека

Рисунок 6.22. Увеличение области стека на 1 Кбайт


переводится в состояние "загрузки в память", при котором данные для области
считываются из файла в память с помощью встроенной модификации алгоритма
системной функции read.
Если ядро загружает область команд, которая может разделяться нескольки-
ми процессами, возможна ситуация, когда процесс попытается воспользоваться
областью до того, как ее содержимое будет полностью загружено, так как про-
цесс загрузки может приостано-
виться во время чтения файла. Подробно о том, как это происходит и почему
при этом нельзя использовать блокировки, мы поговорим, когда будем вести
речь о функции exec в следующей главе и в главе 9. Чтобы устранить эту проб-
лему, ядро проверяет статус области и не разрешает к ней доступ до тех пор,
пока загрузка области не будет закончена. По завершении реализации алгоритма
loadreg ядро возобновляет выполнение всех процессов, ожидающих окончания
загрузки области, и изменяет статус области ("готова, загружена в память").
Предположим, например, что ядру нужно загрузить текст размером 7K в об-
ласть, присоединенную к процессу по виртуальному адресу 0, но при этом оста-
вить промежуток размером 1 Кбайт от начала области (Рисунок 6.24). К этому


165

+------------------------------------------------------------+
| алгоритм loadreg /* загрузка части файла в область */ |
| входная информация: (1) указатель на точку входа в частную|
| таблицу областей процесса |
| (2) виртуальный адрес загрузки |
| (3) указатель индекса файла |
| (4) смещение в байтах до начала считы-|
| ваемой части файла |
| (5) объем загружаемых данных в байтах |
| выходная информация: отсутствует |
| { |
| увеличить размер области до требуемой величины (алгоритм|
| growreg); |
| записать статус области как "загружаемой в память"; |
| снять блокировку с области; |
| установить в пространстве процесса значения параметров |
| чтения из файла: |
| виртуальный адрес, по которому будут размещены счи-|
| тываемые данные; |
| смещение до начала считываемой части файла; |
| объем данных, считываемых из файла, в байтах; |
| загрузить файл в область (встроенная модификация алго- |
| ритма read); |
| заблокировать область; |
| записать статус области как "полностью загруженной в па-|
| мять"; |
| возобновить выполнение всех процессов, ожидающих оконча-|
| ния загрузки области; |
| } |
+------------------------------------------------------------+

Рисунок 6.23. Алгоритм загрузки данных области из файла


времени ядро уже выделило запись в таблице областей и присоединило область
по адресу 0 с помощью алгоритмов allocreg и attachreg. Теперь же ядро запус-
кает алгоритм loadreg, в котором действия алгоритма growreg выполняются
дважды - во-первых, при выделении в начале области промежутка в 1 Кбайт, и
во-вторых, при выделении места для содержимого области - и алгоритм growreg
назначает для области таблицу страниц. Затем ядро заносит в соответствующие
поля пространства процесса установочные значения для чтения данных из файла:
считываются 7 Кбайт, начиная с адреса, указанного в виде смещения внутри
файла (параметр алгоритма), и записываются в виртуальное пространство про-
цесса по адресу 1K.

Частная таблица областей Частная таблица областей
процесса процесса
+-------+----------+------+ +-------+----------+------+
| Адрес | Виртуаль-| Раз- | | Адрес | Виртуаль-| Раз- |
| табли-| ный адрес| мер | | табли-| ный адрес| мер |
| цы | в прост- | и | | цы | в прост- | и |
| стра- | ранстве | защи-| | стра- | ранстве | защи-|
| ниц | процесса | та | | ниц | процесса | та |
+-------+----------+------+ +-------+----------+------+
Текст| --- | | 0 | | | 0 | 8 |
+-------+----------+------+ +---+---+----------+------+
(а) Запись таблицы в перво- +--+
начальном виде |
v

166



+-------------+
| пусто |
Частная таблица областей +-------------+
процесса | 779K |
+-------+----------+------+ +-------------+
| Адрес | Виртуаль-| Раз- | | 846K |
| табли-| ный адрес| мер | +-------------+
| цы | в прост- | и | | 752K |
| стра- | ранстве | защи-| +-------------+
| ниц | процесса | та | | 341K |
+-------+----------+------+ +-------------+
| | 0 | 1 | | 484K |
+---+---+----------+------+ +-------------+
+--+ | 976K |
| +-------------+
v | 794K |
+-------------+ +-------------+
| пусто | | |
+-------------+ +-------------+
(б) Запись, указывающая на (в) После второго выполне-
промежуток в начале об- ния алгоритма growreg
ласти (после первого
выполнения алгоритма
growreg)


Рисунок 6.24. Загрузка области команд (текста)




+------------------------------------------------------------+
| алгоритм freereg /* освобождение выделенной области */|
| входная информация: указатель на (заблокированную) область|
| выходная информация: отсутствует |
| { |
| если (счетчик ссылок на область имеет ненулевое значе- |
| ние) |
| { |
| /* область все еще используется одним из процессов */|
| снять блокировку с области; |
| если (область ассоциирована с индексом) |
| снять блокировку с индекса; |
| возвратить управление; |
| } |
| если (область ассоциирована с индексом) |
| освободить индекс (алгоритм iput); |
| освободить связанную с областью физическую память; |
| освободить связанные с областью вспомогательные таблицы;|
| очистить поля области; |
| включить область в список свободных областей; |
| снять блокировку с области; |
| } |
+------------------------------------------------------------+


Рисунок 6.25. Алгоритм освобождения области

167

    6.5.6 Освобождение области



Если область не присоединена уже ни к какому процессу, она может быть
освобождена ядром и возвращена в список свободных областей (Рисунок 6.25).
Если область связана с индексом, ядро освобождает и индекс с помощью алго-
ритма iput, учитывая значение счетчика ссылок на индекс, установленное в ал-
горитме allocreg. Ядро освобождает все связанные с областью физические ре-
сурсы, такие как таблицы страниц и собственно страницы физической памяти.
Предположим, например, что ядру нужно освободить область стека, описанную на
Рисунке 6.22. Если счетчик ссылок на область имеет нулевое значение, ядро
освободит 7 страниц физической памяти вместе с таблицей страниц.

+------------------------------------------------------------+
| алгоритм detachreg /* отсоединить область от процесса */ |
| входная информация: указатель на точку входа в частной |
| таблице областей процесса |
| выходная информация: отсутствует |
| { |
| обратиться к вспомогательным таблицам процесса, имеющим |
| отношение к распределению памяти, |
| освободить те из них, которые связаны с областью; |
| уменьшить размер процесса; |
| уменьшить значение счетчика ссылок на область; |
| если (значение счетчика стало нулевым и область не явля-|
| ется неотъемлемой частью процесса) |
| освободить область (алгоритм freereg); |
| в противном случае /* либо значение счетчика отлично |
| от 0, либо область является не- |
| отъемлемой частью процесса */ |
| { |
| снять блокировку с индекса (ассоциированного с об- |
| ластью); |
| снять блокировку с области; |
| } |
| } |
+------------------------------------------------------------+

Рисунок 6.26. Алгоритм отсоединения области


    6.5.7 Отсоединение области от процесса



Ядро отсоединяет области при выполнении системных функций exec, exit и
shmdt (отсоединить разделяемую память). При этом ядро корректирует соответс-
твующую запись и разъединяет связь с физической памятью, делая недействи-
тельными связанные с областью регистры управления памятью (алгоритм
detachreg, Рисунок 6.26). Механизм преобразования адресов после этого будет
относиться уже к процессу, а не к области (как в алгоритме freereg). Ядро
уменьшает значение счетчика ссылок на область и значение поля, описывающего
размер процесса в записи таблицы процессов, в соответствии с размером облас-