Напомним, что если область при выполнении алгоритма allocreg (Раздел 6.5.2) выделяется впервые, ядро увеличивает значение счетчика ссылок на индекс, ассоциированный с областью, при этом значение счетчика ссылок нами уже было увеличено в самом начале выполнения функции exec (алгоритм namei). Поскольку ядро уменьшает значение счетчика только один раз в завершение выполнения функции exec (по алгоритму iput), значение счетчика ссылок на индекс файла, ассоциированного с разделяемой областью команд и исполняемого в настоящий момент, равно по меньшей мере 1. Поэтому когда процесс разрывает связь с файлом (функция unlink), содержимое файла остается нетронутым (не претерпевает изменений). После загрузки в память сам файл ядру становится ненужен, ядро интересует только указатель на копию индекса файла в памяти, содержащийся в таблице областей; этот указатель и будет идентифицировать файл, связанный с областью. Если бы значение счетчика ссылок стало равным 0, ядро могло бы передать копию индекса в памяти другому файлу, тем самым делая сомнительным значение указателя на индекс в записи таблицы областей: если бы пользователю пришлось исполнить новый файл, используя функцию exec, ядро по ошибке связало бы его с областью команд старого файла. Эта проблема устраняется благодаря тому, что ядро при выполнении алгоритма allocreg увеличивает значение счетчика ссылок на индекс, предупреждая тем самым переназначение индекса в памяти другому файлу. Когда процесс во время выполнения функций exit или exec отсоединяет область команд, ядро уменьшает значение счетчика ссылок на индекс (по алгоритму freereg), если только связь индекса с областью не помечена как «неотъемлемая».
алгоритм xalloc /* выделение и инициализация области команд */
входная информация: индекс исполняемого файла
выходная информация: отсутствует
{
if (исполняемый файл не имеет отдельной области команд)
return;
if (уже имеется область команд, ассоциированная с индексом исполняемого файла)
{
/* область команд уже существует… подключиться к ней */
заблокировать область;
do while (содержимое области еще не доступно)
{
/* операции над счетчиком ссылок, предохраняющие от глобального удаления области */
увеличить значение счетчика ссылок на область;
снять с области блокировку;
sleep (пока содержимое области не станет доступным);
заблокировать область;
уменьшить значение счетчика ссылок на область;
}
присоединить область к процессу (алгоритм attachreg);
снять с области блокировку;
return;
}
/* интересующая нас область команд не существует — создать новую */
выделить область команд (алгоритм allocreg); /* область заблокирована */
if (область помечена как «неотъемлемая»)
отключить соответствующий флаг;
подключить область к виртуальному адресу, указанному в заголовке файла (алгоритм attachreg);
if (файл имеет специальный формат для системы с замещением страниц) /* этот случай будет рассмотрен в главе 9 */
else /* файл не имеет специального формата */
считать команды из файла в область (алгоритм loadreg);
изменить режим защиты области в записи частной таблицы областей процесса на «read-only»;
снять с области блокировку;
}
Рисунок 7.23. Алгоритм выделения областей команд
Рисунок 7.24. Взаимосвязь между таблицей индексов и таблицей областей в случае совместного использования процессами одной области команд
Рассмотрим в качестве примера ситуацию, приведенную на Рисунке 7.21, где показана взаимосвязь между структурами данных в процессе выполнения функции exec по отношению к файлу «/bin/date» при условии расположения команд и данных файла в разных областях. Когда процесс исполняет файл «/bin/date» первый раз, ядро назначает для команд файла точку входа в таблице областей (Рисунок 7.24) и по завершении выполнения функции exec оставляет счетчик ссылок на индекс равным 1. Когда файл «/bin/date» завершается, ядро запускает алгоритмы detachreg и freereg, сбрасывая значение счетчика ссылок в 0. Однако, если ядро в первом случае не увеличило значение счетчика, оно по завершении функции exec останется равным 0 и индекс на всем протяжении выполнения процесса будет находиться в списке свободных индексов. Предположим, что в это время свободный индекс понадобился процессу, запустившему с помощью функции exec файл «/bin/who», тогда ядро может выделить этому процессу индекс, ранее принадлежавший файлу «/ bin/date». Просматривая таблицу областей в поисках индекса файла «/bin/who», ядро вместо него выбрало бы индекс файла «/bin/date». Считая, что область содержит команды файла «/bin/who», ядро исполнило бы совсем не ту программу. Поэтому значение счетчика ссылок на индекс активного файла, связанного с разделяемой областью команд, должно быть не меньше единицы, чтобы ядро не могло переназначить индекс другому файлу.
Читать дальше