Операционные системы. Управление ресурсами

       

Многосегментная модель


Расширим модель, рассмотренную в предыдущем разделе на случай N сегментов.

Виртуальное пространство процесса разбивается на сегменты, которые нумеруются от 0 до N-1. Виртуальный адрес, таким образом, состоит из двух частей: номера сегмента и смещения в сегменте. Эти части могут либо представляться по отдельности каждая, либо упаковываться в одно адресное слово, в котором определенное число старших разрядов будет интерпретироваться как номер сегмента, а оставшаяся часть - как смещение. В первом случае сегменты могут размещаться произвольным образом в виртуальном адресном пространстве. Во втором случае создается впечатление плоского адресного пространства с адресами от 0 до максимально возможного при данной разрядности виртуального адреса, но в этом пространстве могут быть дыры - виртуальные адреса для процесса недоступные - из-за отсутствия соответствующих сегментов или из-за сегментов, длина которых меньше максимально возможной.

Количество сегментов и максимальный размер сегмента ограничивается аппаратурой - разрядностью полей адресного слова. При выделении процессу реальной памяти каждый сегмент размещается в непрерывной области реальной памяти, но сегменты, смежные в виртуальной памяти, могут попадать в несмежные области памяти реальной. Теперь для процесса уже недостаточно одного дескриптора сегмента - он должен иметь таблицу таких дескрипторов в составе своего блока контекста. Аппаратный регистр дескриптора сегмента превращается в регистр адреса таблицы дескрипторов, он хранит указатель на таблицу дескрипторов активного процесса и перезагружается при смене активного процесса. Вычисление реального адреса аппаратурой несколько усложняется, как показано на Рисунке 3.5:

  • выбирается сегментная часть виртуального адреса, она служит индексом в таблице дескрипторов; по индексу выбирается запись той таблицы, адрес которой находится в регистре адреса таблицы дескрипторов;
  • выбранная запись является дескриптором сегмента, часть виртуального адреса, соответствующая смещению, сравнивается с полем длины в дескрипторе;
  • если смещение в сегменте не превышает его длины, вычисляется реальный адрес как сумма базового адреса из дескриптора сегмента и смещения из виртуального адреса.


Примерная структура аппаратно поддерживаемого дескриптора сегмента приведена на Рисунке 3.6. Подчеркиваем, что данная структура не является обязательной, для всех компьютерных архитектур, мы привели лишь наиболее распространенный ее вариант и использовали наиболее часто употребляемые имена полей.



Рис.3.5. Трансляция адресов. Многосегментная модель


Рис.3.6. Примерная структура дескриптора сегмента
Допустимое количество сегментов определяется разрядностью соответствующего поля виртуального адреса и может быть весьма большим. Либо аппаратура должна иметь специальный регистр размера таблицы дескрипторов (такой регистр есть в Intel-Pentium), либо ОС должна подготавливать для процесса таблицу максимально возможного размера, отмечая в ней дескрипторы несуществующих сегментов (например, нулевым значением поля size). Отметим, что для систем, упаковывающих номер сегмента и смещение в одно адресное число, разрядность смещения не является ограничением на длину виртуального сегмента. Виртуальный сегмент большего размера представляется в таблице двумя и более обязательно смежными дескрипторами. С точки зрения процесса он обращается к одному сегменту, задавая в нем большое смещение, на самом же деле переполнение поля смещения переносится в поле номера сегмента. Если же простая двоичная арифметика не обеспечивает модификацию номера сегмента, возможность работы с большими сегментами может поддерживаться ОС путем особой обработки прерывания-ловушки "защита памяти".

Каковы преимущества многосегментной модели памяти?

Самое первое преимущество заключается в том, что у процесса появляется возможность разместить данные, обрабатываемые различным образом, в разных сегментах своего виртуального пространства (так, в ОС Unix, например, каждый процесс имеет при начале выполнения три сегмента: кодов, данных и стека). Каждому сегменту могут быть определены свои права доступа. Поскольку обращения к памяти могут быть трех видов: чтение, запись и передача управления, то для описания прав доступа достаточно 3-битного поля Read-Write-eXecute, каждый разряд которого определяет разрешение одного из видов доступа.




Аппаратные средства большинства архитектур обеспечивают контроль права доступа при трансляции адресов: поле прав доступа включается в дескриптор сегмента и, если поступивший вид обращения не разрешен, то выполняется прерывание-ловушка "нарушение доступа".

Другое важное преимущество многосегментной модели заключается в том, что процесс имеет возможность использовать виртуальное адресное пространство, размер которого больше, чем размер доступной реальной памяти. Это достигается за счет того, что не обязательно все сегменты процесса должны одновременно находиться в реальной памяти. Дескриптор каждого сегмента содержит бит present, который установлен в 1, если сегмент подкачан в оперативную память, или в 0 - если сегмент вытеснен из нее. Аппаратура трансляции адресов проверяет этот бит и при нулевом его значении выполняет прерывание-ловушку "отсутствие сегмента" (segment falure). В отличие от большинства других ловушек, которые в основном сигнализируют об ошибках, при которых дальнейшее выполнение процесса невозможно, эта не приводит к фатальным для процесса последствиям. ОС, обрабатывая это прерывание, находит образ вытесненного сегмента на внешней памяти, и подкачивает его в реальную память. Естественно, что процесс, обратившийся к вытесненному сегменту, переводится в ожидание, это ожидание может затянуться, если у ОС имеются проблемы с ресурсом реальной памяти. Когда сегмент будет подкачан, процесс перейдет в очередь готовых и будет активизирован вновь с той команды, которая вызвала прерывание-ловушку. В тех аппаратных системах, которые не обрабатывают бит присутствия в дескрипторе сегмента, можно вместо него использовать поле size: ОС должна сбрасывать это поле в 0 при вытеснении сегмента и восстанавливать при его подкачке.

Естественно, что для подкачки сегмента ОС должна знать его адрес на внешней памяти. Подавляющее большинство систем не поддерживают аппаратно поле внешнего адреса в дескрипторе сегмента. Для хранения его ОС может либо использовать поле base, либо хранить этот адрес в расширении таблицы дескрипторов, в котором для каждого сегмента хранится информация о нем, обрабатываемая только программно.


В том же расширении может храниться истинное значение поля size при использовании его вместо поля present.

Очевидно, что в многосегментной модели свопинг приобретает более интенсивный характер. Следовательно, эффективность стратегий управления памятью имеет еще больший вес. Поскольку в реальной памяти размещаются сегменты разной длины, проблемы размещения остаются те же. Для многосегментной организации характерны внешние дыры, борьба с которыми ведется перемещением сегментов. Если перемещение сегментов не освобождает такого количества реальной памяти, которое требуется для удовлетворения запроса, ОС может принять решение о вытеснении какого-либо сегмента и освобождении занимаемой им реальной памяти. Некоторые системы (Unix) вытесняют из памяти какой-либо процесс целиком со всеми принадлежащими ему сегментами, но такое решение может быть эффективным только в том случае, если процессы имеют по незначительному числу сегментов каждый. Стратегии вытеснения мы подробно рассмотрим позже - в страничной модели памяти.

Отметим, что вытеснение сегмента - не обязательно долгий процесс. Если сегмент не имеет прав доступа для записи, то он содержит команды или статические инициализированные данные, копия этого сегмента уже есть на внешней памяти - в файле, содержащем загрузочный образ процесса. Поэтому вытеснение такого сегмента не сопровождается перезаписью его на внешнюю память. Даже если в сегмент и разрешена запись, то, возможно, запись еще не производилась, такой сегмент тоже незачем перезаписывать на внешнюю память. Поля used и dirty в дескрипторе сегмента используются при принятии стратегических решений о вытеснении.

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

В многосегментной модели значительно увеличивается объем управляющей информации, сохраняемой в блоке контекста процесса, даже когда процесс не выполняется. Реальная память, занимаемая блоками контекста неактивных и даже полностью вытесненных процессов, не может быть отдана другим процессам.


Такие участки памяти носят название заголовочных дыр. Если потери реальной памяти на заголовочные дыры оказываются недопустимо большими, то имеет смысл разбить блок контекста процесса на две части: меньшую, обязательно сохраняемую в реальной памяти, и большую, которая может быть вытеснена. В литературе [21, 30] описана ОС MULTICS, в которой для номера сегмента отводилось 18 двоичных разрядов. Таблица сегментов процесса могла быть настолько большой, что и одна она не помешалась в оперативной памяти. Для преодоления этого противоречия таблица сегментов разбивалась на страницы, которые подвергались свопингу. (ОС MULTICS была признана неудачным проектом и не получила широкого распространения, но значительно повлияла на последующие проекты ОС, прежде всего - на Unix.)

Чрезвычайно важным преимуществом многосегментной модели является возможность разделения (совместного использования) сегментов процессами. Процессы могут быть разработаны так, чтобы виртуальные пространства двух или более процессов перекрывались в каких-то областях. Процессы могут использовать общее виртуальное пространство для обмена данными. Реализация этой возможности в какой-то мере зависит от аппаратных средств. Во многих вычислительных системах процесс может работать с несколькими таблицами дескрипторов, поскольку в системе имеется несколько регистров адресов таблиц (так в процессоре Intel 80286 и последующих предусмотрены две таблицы, называемые локальной и глобальной). Решение, использующее это свойство, заключается в том, что дескриптор разделяемого сегмента помещается в общую для всех процессов (глобальную) таблицу, такой сегмент может быть доступным для всех процессов и имеет общий виртуальный номер для всех процессов. Другое решение, возможное и при наличии только одной таблицы для каждого процесса, заключается в том, что для общего сегмента создается по записи в таблице каждого процесса, с ним работающего, для каждого процесса этот сегмент имеет свой виртуальный номер. Второе решение представляется более удачным с точки зрения защиты, так как , во-первых, доступ к сегменту имеют только те процессы, в таблицах которых созданы соответствующие дескрипторы, во-вторых, есть возможность дать разным процессам разные права доступа к разделяемому сегменту.


Но за такое решение приходится платить тем, что при свопинге разделяемого сегмента и при учете его использования необходимо корректировать его дескрипторы в таблицах всех процессов.

Что касается стратегии подкачки, то все ОС применяют в сегментной модели "ленивую" политику: вытесненный сегмент подкачивается в реальную память только при обращении к нему. Некоторые системы (например, OS/2) позволяют управлять начальной подкачкой сегментов при запуске процесса: сегмент может быть определен программистом как предварительно загружаемый (preload) или загружаемый по вызову (load on call). Разработать неубыточную стратегию упреждающей (до обращения) подкачки сегментов при свопинге пока не представляется возможным из-за отсутствия надежных методов предсказания того, к какому сегменту будет обращение в ближайшем будущем.

В многосегментной модели процесс имеет возможность динамически изменять структуру своего виртуального адресного пространства. Для этих целей ему должен быть доступен минимальный набор системных вызовов, приводимый ниже.

Получить сегмент:

seg = getSeg (segsize, access);

ОС выделяет новый сегмент заданного размера и с заданными правами доступа и возвращает процессу виртуальный номер выделенного сегмента.

Освободить сегмент:

freeSeg(seg);

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

Изменить размер сегмента:

chSegSize(seg, newsize).

Изменить права доступа к сегменту:

chSegAccess(seg, newaccess).

В конкретных системах этот минимальный набор может быть расширен дополнительным системным сервисом.

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




Содержание раздела