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

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

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

Став активным, init считывает файл /etc/ttytab, в котором перечислены все возможные устройства-терминалы. Если какое-либо устройство может быть использовано как терминал для входа в систему (в стандартной поставке это только консоль), то в /etc/ttytab у него присутствует запись в поле getty. Для каждого такого терминала init запускает дочерний процесс. Обычно каждый из этих дочерних процессов запускает программу /usr/bin/getty, которая печатает приглашение и ждет, когда пользователь введет свое имя. После этого вызывается программа /usr/bin/login, которой в качестве аргумента передается введенное имя. Если же для определенного терминала требуются какие-то специальные действия (например, это телефонное подключение), то в /etc/ttytab можно указать команду (например, /usr/bin/stty), которая будет выполнена перед запуском getty.

Если вход в систему осуществлен успешно, /bin/login запускает оболочку пользователя, имя которой указывается в файле /etc/passwd, обычно это /bin/sh или /usr/bin/ash. Оболочка воспринимает и интерпретирует вводимые пользователем команды, запуская для их исполнения новые процессы. Таким образом, оболочки являются прямыми потомками init, пользовательские процессы являются его внуками , а все процессы вместе образуют единое дерево.

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

Вся информация о процессах хранится в таблице процессов, поля которой поделены между ядром, менеджером памяти и файловой системой. Когда появляется новый процесс (при помощи fork) или же когда процесс завершается (по системному вызову exit или по сигналу), то прежде всего свои поля в таблице процессов обновляет менеджер памяти. Затем он посылает ядру и файловой системе указания поступить таким же образом.

2.5.3. Взаимодействие между процессами в MINIX

Для отправки и приема сообщений предусмотрено три примитива. Им соответствуют следующие процедуры языка С:

♦ send(dest Smessage); - отправляет сообщение процессу dest,



f receive(source, Smessage); - принимает сообщение от процесса source (или от ANY),

f send rec(src dst Smessage); - отправляет сообщение и ждет ответа от процесса.

У всех трех вызовов во втором аргументе передается локальный адрес данных сообщения. Механизм передачи сообщений в ядре копирует эти данные из буфера отправителя в буфер приемника. При использовании send rec ответ записывается поверх исходного сообщения. В принципе, механизм передачи сообщений в ядре можно было бы переделать так, чтобы обмениваться ими через сеть и тем самым реализовать распределенную систему. На практике это осложняется тем, что сообщения обычно содержат указатели на большие структуры данных и в распределенной системе необходимо реализовать механизм копирования этих данных через сеть.

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

Когда процесс отправляет сообщение (что также касается и задач, как специального случая процесса), он блокируется до тех пор, пока адресат не сделает вызов receive. Другими словами, в MINIX во избежание проблем с буферизацией отправленных, но еще не принятых сообщений применяется метод рандеву. Эта схема обеспечивает меньшую гибкость, чем модель с буферизацией, но она вполне адекватна и гораздо проще в реализации, так как не требуется никакой работы с буферами.

2.5.4. Планирование процессов в MINIX

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

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



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

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

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

2.6. Реализация процессов в MINIX

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

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

2.6.1. Структура исходного кода MINIX

Исходные коды системы логически разбиты на два каталога. В стандартной системе это /usr/include и /usr/src/. Реальное их размещение может быть другим, но структура в любой системе всегда одинакова. Ссылаясь на эти каталоги, мы будем называть их include/ и src/ соответственно.

В каталоге include/ расположено несколько стандартных заголовочных файлов POSIX. Кроме того, в нем есть три вложенных каталога:

1. sys/ - здесь содержатся дополнительные заголовочные файлы POSIX.

2. minix/ - заголовочные файлы операционной системы.

3. ibm/ - заголовочные файлы с определениями, специфичными для IBM PC.

Для поддержки расширения MINIX и программ, работающих в MINIX-среде, в каталог include/ включены и другие подкаталоги, имеющиеся на компакт-диске или в Интернете. Например, для поддержки сетевых расширений предусмотрен



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.
Копирование материалов разрешено исключительно при условии цититирования.