Архитектура операционной системы UNIX (ЛП) - Бах Морис Дж.
Шрифт:
Интервал:
Закладка:
Расположение команд и данных в разных областях облегчает поиск и предотвращение ошибок адресации. Тем не менее, в ранних версиях системы UNIX команды и данные разрешалось располагать в одной области, поскольку на машинах PDP размер процесса был сильно ограничен: программы имели меньший размер и существенно меньшую сегментацию, если команды и данные занимали одну и ту же область. В последних версиях системы таких строгих ограничений на размер процесса нет и в дальнейшем возможность загрузки команд и данных в одну область компиляторами не будет поддерживаться.
Второе преимущество раздельного хранения команд и данных состоит в возможности совместного использования областей процессами. Если процесс не может вести запись в область команд, команды процесса не претерпевают никаких изменений с того момента, как ядро загрузило их в область команд из командной секции исполняемого файла. Если один и тот же файл исполняется несколькими процессами, в целях экономии памяти они могут иметь одну область команд на всех. Таким образом, когда ядро при выполнении функции exec отводит область под команды процесса, оно проверяет, имеется ли возможность совместного использования процессами команд исполняемого файла, что определяется «магическим числом» в заголовке файла. Если да, то с помощью алгоритма xalloc ядро ищет существующую область с командами файла или назначает новую в случае ее отсутствия (см. Рисунок 7.23).
Исполняя алгоритм xalloc, ядро просматривает список активных областей в поисках области с командами файла, индекс которого совпадает с индексом исполняемого файла. В случае ее отсутствия ядро выделяет новую область (алгоритм allocreg), присоединяет ее к процессу (алгоритм attachreg), загружает ее в память (алгоритм loadreg) и защищает от записи (read-only). Последний шаг предполагает, что при попытке процесса записать что-либо в область команд будет получен отказ, вызванный системой защиты памяти. В случае обнаружения области с командами файла в списке активных областей осуществляется проверка ее наличия в памяти (она может быть либо загружена в память, либо выгружена из памяти) и присоединение ее к процессу. В завершение выполнения алгоритма xalloc ядро снимает с области блокировку, а позднее, следуя алгоритму detachreg при выполнении функций exit или exec, уменьшает значение счетчика областей. В традиционных реализациях системы поддерживается таблица команд, к которой ядро обращается в случаях, подобных описанному. Таким образом, совокупность областей команд можно рассматривать как новую версию этой таблицы.
Напомним, что если область при выполнении алгоритма 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», ядро исполнило бы совсем не ту программу. Поэтому значение счетчика ссылок на индекс активного файла, связанного с разделяемой областью команд, должно быть не меньше единицы, чтобы ядро не могло переназначить индекс другому файлу.