Главная страница  Межпроцессное взаимодействие (состязание) 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 [ 127 ] 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

на рис. 4.29. В каждый момент времени работающая программа находится на определенном уровне, что отмечается 2-битовым полем в его регистре слова состояния программы (PSW). Каждый сегмент в системе также имеет свой уровень.


Типичное .употребпение уровней

Уровень

Рис. 4.29. Защита в системе Pentium

До тех пор пока программа сама ограничивает использование сегментов на своем собственном уровне, система прекрасно работает. Разрешаются попытки получения доступа к данным высшего уровня. Попытки доступа к данным более низкого уровня запрещены и вызывают прерывания. Попытки вызвать процедуры различного уровня (более высокого или низкого) позволяются, но тщательно контролируемым образом. Чтобы сделать межуровневый вызов, инструкция CALL должна содержать селектор вместо адреса. Этот селектор определяет дескриптор, называемый шлюзом вызова (call gate) и передающий адрес вызываемой процедуры. Таким образом, перепрыгнуть в середину произвольного сегмента кода другого уровня невозможно, открыты лишь официальные точки входа. Концепция уровней защиты и схем вызова впервые появилась в системе MULTICS, где они представали в виде колец защиты.

Типичное использование этого механизма представлено на рис. 4.29. На уровне О мы находим ядро операционной системы, занимающееся обработкой операций ввода/вывода, управлением памятью и другими первоочередными вопросами. На уровне 1 находится обработчик системных вызовов. Пользовательские программы этого уровня могут обращаться к процедурам для выполнения системных вызовов, но только к определенному и защищенному списку процедур. Уровень 2 содержит библиотечные процедуры, возможно, совместно используемые несколькими работающими программами. Пользовательские программы



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

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

4.7. Обзор управления памятью в MINIX

В MINIX управление памятью реализовано просто: ни свопинг, ни страничная организация не используются. Менеджер памяти поддерживает список свободных участков ( дыр ), отсортированный по адресам. Когда процессу вследствие вызова fork или exec требуется память, элементы списка перебираются до тех пор, пока не будет найдена первая достаточно большая дыра. Расположившись в памяти, процесс всегда остается на прежнем месте до своего завершения. Он никогда не выгружается на диск и не перемещается по другому адресу. Кроме того, он никогда не увеличивает и не уменьшает выделенную ему область памяти.

Такая стратегия требует некоторых пояснений. Ее определяют три фактора: (1) MINIX предназначена для персональных компьютеров, а не для больших систем с разделением времени, (2) MINIX должна работать на всех PC, и (3) система должна быть простой, чтобы ее можно было реализовать на всех малых компьютерах.

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

Желание заставить MINIX работать на всех IBM-совместимых компьютерах также оказало большое влияние на выбор стратегии менеджера памяти. Простейшим в этом семействе является процессор 8086, с очень примитивной архитектурой. Он ни в какой форме не поддерживает виртуальную память и даже не обнаруживает переполнение стека. В более поздних процессорах, 80386, 80486 и Pentium, таких ограничений нет, но если взять на вооружение их возможности, MINIX станет несовместима с 8086.

С позиций переносимости, схема управления памятью должна быть до нельзя простой. Если бы MINIX опиралась на страничную организацию или сегментацию, перенести систему на машины без таких возможностей было бы сложно. Чем меньше предположений о потенциале оборудования закладывается в систему, тем шире становится круг платформ, на которые ее можно перенести.

Еще одной необычной особенностью MINIX является способ реализации менеджера памяти. Последний не является частью ядра. Управлением памятью занимается отдельный процесс, работающий в адресном пространстве пользова-



теля и взаимодействующий с ядром при помощи стандартного механизма сообщений. На рис. 2.24 менеджер памяти находится на уровне серверов.

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

Большая часть кода менеджера памяти в MINIX посвящена обработке системных вызовов, связанных с управлением памятью (в основном это fork и exec), а не манипулированию списками процессов и свободных блоков памяти. В следующем разделе мы изучим распределение памяти, а еще дальше последует обзор того, как в MINIX выполняются системные вызовы, обрабатываемые менеджером памяти.

4.7.1. Распределение памяти

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

В MINIX память выделяется в двух ситуациях. Во-первых, когда процесс разветвляется, дочернему процессу предоставляется необходимая ему память. Во-вторых, когда процесс при помощи системного вызова exec заменяет свой образ, старый образ памяти процесса возвращается в список свободных блоков памяти, а новая память выделяется на новом месте. Положение нового образа процесса в памяти будет зависеть от того, где найден первый подходящий по размеру блок. Кроме того, когда процесс завершается (самостоятельно или принудительно, по сигналу), занятая им память освобождается.

На рис. 4.30 показаны оба варианта выделения памяти. На рис. 4.30, а мы видим в памяти два процесса, АиВ. Если процесс А разветвляется, мы попадаем в ситуацию на рис. 4.30, б. Дочерний процесс является точной копией процесса А. Если теперь дочерний процесс выполнит файл С, память придет в состояние, показанное на рис. 4.30, в. Образ дочернего процесса был заменен образом С.

Обратите внимание, что область памяти, занимаемая потомком, освобождается перед тем, как выделить память для нового образа, поэтому С может занять память, в которой раньше располагался потомок. Таким образом, после выполнения серии пар вызовов fork и exec все процессы будут соседствовать в памяти впритирку друг к другу. Если бы память для нового образа выделялась первой, между процессами обязательно зияли бы дыры.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 [ 127 ] 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2018 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.