грамм (см. [SVID 85]). Однако действие этих функций похо- же. 158 сохраненный в результате работы алгоритма setjmp, оно исполнит алгоритм longjmp, который восстанавливает контекст из пространства процесса и имеет, как и setjmp, код завершения, равный 1. 6.4.5 Копирование данных между адресным пространством сис- темы и адресным пространством задачи До сих пор речь шла о том, что процесс выполняется в режиме ядра или в режиме задачи без каких-либо перекрытий (пересечений) между режимами. Одна- ко, при выполнении большинства системных функций, рассмотренных в последней главе, между пространством ядра и пространством задачи осуществляется пере- сылка данных, например, когда идет копирование параметров вызываемой функции из пространства задачи в пространство ядра или когда производится передача данных из буферов ввода-вывода в процессе выполнения функции read. На многих машинах ядро системы может непосредственно ссылаться на адреса, принадлежа- щие адресному пространству задачи. Ядро должно убедиться в том, что адрес, по которому производится запись или считывание, доступен, как будто бы рабо- та ведется в режиме задачи; в противном случае произошло бы нарушение стан- дартных методов защиты и ядро, пусть неумышленно, стало бы обращаться к ад- ресам, которые находятся за пределами адресного пространства задачи (и, воз- можно, принадлежат структурам данных ядра). Поэтому передача данных между пространством ядра и пространством задачи является "дорогим предприятием", требующим для своей реализации нескольких команд. +--------------------------------------------------------+ | fubyte: # пересылка байта из | | # пространства задачи | | prober $3,$1,*4(ap) # байт доступен ? | | beql eret # нет | | movzbl *4(ap),r0 | | ret | | eret: | | mnegl $1,r0 # возврат ошибки (-1) | | ret | +--------------------------------------------------------+ Рисунок 6.17. Пересылка данных из пространства задачи в пространство ядра в системе VAX На Рисунке 6.17 показан пример реализованной в системе VAX программы пе- ресылки символа из адресного пространства задачи в адресное пространство яд- ра. Команда prober проверяет, может ли байт по адресу, равному (регистр ука- зателя аргумента + 4), быть считан в режиме задачи (режиме 3), и если нет, ядро передает управление по адресу eret, сохраняет в нулевом регистре -1 и выходит из программы; при этом пересылки символа не происходит. В противном случае ядро пересылает один байт, находящийся по указанному адресу, в ре- гистр 0 и возвращает его в вызывающую программу. Пересылка 1 символа потре- бовала пяти команд (включая вызов функции с именем fubyte). 6.5 УПРАВЛЕНИЕ АДРЕСНЫМ ПРОСТРАНСТВОМ ПРОЦЕССА В этой главе мы пока говорили о том, каким образом осуществляется перек- лючение контекста между процессами и как контекстные уровни запоминаются в стеке и выбираются из стека, представляя контекст пользовательского уровня как статический объект, не претерпевающий изменений при восстановлении кон- текста процесса. Однако, с виртуальным адресным пространством процесса рабо- 159 тают различные системные функции и, как будет показано в следующей главе, выполняют при этом операции над областями. В этом разделе рассматривается информационная структура области; системные функции, реализующие операции над областями, будут рассмотрены в следующей главе. Запись таблицы областей содержит информацию, необходимую для описания области. В частности, она включает в себя следующие поля: * Указатель на индекс файла, содержимое которого было первоначально загру- жено в область * Тип области (область команд, разделяемая память, область частных данных или стека) * Размер области * Местоположение области в физической памяти * Статус (состояние) области, представляющий собой комбинацию из следующих признаков: - заблокирована - запрошена - идет процесс ее загрузки в память - готова, загружена в память * Счетчик ссылок, в котором хранится количество процессов, ссылающихся на данную область. К операциям работы с областями относятся: блокировка области, снятие блокировки с области, выделение области, присоединение области к пространст- ву памяти процесса, изменение размера области, загрузка области из файла в пространство памяти процесса, освобождение области, отсоединение области от пространства памяти процесса и копирование содержимого области. Например, системная функция 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). Ядро уменьшает значение счетчика ссылок на область и значение поля, описывающего размер процесса в записи таблицы процессов, в соответствии с размером облас- ти. Если значение счетчика становится равным 0 и если нет причины оставлять область без изменений (область не является областью разделяемой памяти или областью команд с признаками неотъемлемой части процесса, о чем будет идти речь в разделе 7.5), ядро освобождает область по алгоритму freereg. В про- тивном случае ядро снимает с индекса и с области блокировку, установленную для того, чтобы предотвратить конкуренцию между параллельно выполняющимися процессами (см. раздел 7.5), но оставляет область и ее ресурсы без измене- ний. 168 Частные таблицы областей процессов Области +--------------+ +-------------+ Команды | +-------------->| Разделяемая | +--------------+ +------->+-------------+ Данные | +----+ | +--------------+ | | +-------------+ Стек | +--+ +-|------->| Частная +-+ +--------------+ | | +-------------+ | Копи- Процесс A | | | рова- | | +-------------+ | ние +---|------->| Частная +-|-+ дан- +--------------+ | +-------------+ | | ных Команды | +------+ | | +--------------+ +-------------+ | | Данные | +-------------->| Частная |<+ | +--------------+ +-------------+ | Стек | +------+ | +--------------+ | +-------------+ | Процесс B +------->| Частная |<--+ +-------------+ Рисунок 6.27. Копирование содержимого области +------------------------------------------------------------+ | алгоритм dupreg /* копирование содержимого существующей | | области */ | | входная информация: указатель на точку входа в таблице об-| | ластей | | выходная информация: указатель на область, являющуюся точ- | | ной копией существующей области | | { | | если (область разделяемая) | | /* в вызывающей программе счетчик ссылок на об- | | ласть будет увеличен, после чего будет испол- | | нен алгоритм attachreg */ | | возвратить (указатель на исходную область); | | выделить новую область (алгоритм allocreg); | | установить значения вспомогательных структур управления| | памятью в точном соответствии со значениями существую-| | щих структур исходной области; | | выделить для содержимого области физическую память; | | "скопировать" содержимое исходной области во вновь соз-| | данную область; | | возвратить (указатель на выделенную область); | | } | +------------------------------------------------------------+ Рисунок 6.28. Алгоритм копирования содержимого существующей области 6.5.8 Копирование содержимого области Системная функция fork требует, чтобы ядро скопировало содержимое облас- тей процесса. Если же область разделяемая (разделяемый текст команд или раз- деляемая память), ядру нет надобности копировать область физически; вместо этого оно увеличивает значение счетчика ссылок на область, позволяя роди- тельскому и порожденному процессам использовать область совместно. Если об- ласть не является разделяемой и ядру нужно физически копировать ее содержи- мое, оно выделяет новую запись в таблице областей, новую таблицу страниц и 169 отводит под создаваемую область физическую память. В качестве примера расс- мотрим Рисунок 6.27, где процесс A порождает с помощью функции fork процесс B и копирует области родительского процесса. Область команд процесса A явля- ется разделяемой, поэтому процесс B может использовать эту область совместно с процессом A. Однако области данных и стека родительского процесса являются его личной принадлежностью (имеют частный тип), поэтому процессу B нужно скопировать их содержимое во вновь выделенные области. При этом даже для об- ластей частного типа физическое копирование области не всегда необходимо, в чем мы убедимся позже (глава 9). На Рисунке 6.28 приведен алгоритм копирова- ния содержимого области (dupreg). 6.6 ПРИОСТАНОВКА ВЫПОЛНЕНИЯ К настоящему моменту мы рассмотрели все функции работы с внутренними структурами процесса, выполняющиеся на нижнем уровне взаимодействия с про- цессом и обеспечивающие переход в состояние "выполнения в режиме ядра" и вы- ход из этого состояния в другие состояния, за исключением функций, переводя- щих процесс в состояние "приостанова выполнения". Теперь перейдем к рассмот- рению алгоритмов, с помощью которых процесс переводится из состояния "выпол- нения в режиме ядра" в состояние "приостанова в памяти" и из состояния при- останова в состояния "готовности к запуску" с выгрузкой и без выгрузки из памяти. +-------------------------------+ | Контекстный уровень ядра 2 | | Исполнить программу пере- | | ключения контекста | | | | Сохранить регистровый кон- | | текст обращения к системной | | функции | Запуск алгоритма приостанова -+-------------------------------+ ^ | Контекстный уровень ядра 1 | | | Исполнить обращение к сис- | | | темной функции | | |