В предыдущей главе нами были рассмотрены сильносвязанные многопроцессор-
ные системы с общей памятью, общими структурами данных ядра и общим пулом,
из которого процессы вызываются на выполнение. Часто, однако, бывает жела-
тельно в целях обеспечения совместного использования ресурсов распределять
процессоры таким образом, чтобы они были автономны от операционной среды и
условий эксплуатации. Пусть, например, пользователю персональной ЭВМ нужно
обратиться к файлам, находящимся на более крупной машине, но сохранить при
этом контроль над персональной ЭВМ. Несмотря на то, что отдельные программы,
такие как uucp, поддерживают передачу файлов по сети и другие сетевые функ-
ции, их использование не будет скрыто от пользователя, поскольку пользова-
тель знает о том, что он работает в сети. Кроме того, надо заметить, что
программы, подобные текстовым редакторам, с удаленными файлами, как с обыч-
ными, не работают. Пользователи должны располагать стандартным набором функ-
ций системы UNIX и, за исключением возможной потери в быстродействии, не
должны ощущать пересечения машинных границ. Так, например, работа системных
функций open и read с файлами на удаленных машинах не должна отличаться от
их работы с файлами, принадлежащими локальным системам.
Архитектура распределенной системы представлена на Рисунке 13.1. Каждый
компьютер, показанный на рисунке, является автономным модулем, состоящим из
ЦП, памяти и периферийных устройств. Соответствие модели не нарушается даже
несмотря на то, что компьютер не располагает локальной файловой системой: он
должен иметь периферийные устройства для связи с другими машинами, а все
принадлежащие ему файлы могут располагаться и на ином компьютере. Физическая
память, доступная каждой машине, не зависит от процессов, выполняемых на
других машинах. Этой особенностью распределенные системы отличаются от силь-
носвязанных многопроцессорных систем, рассмотренных в предыдущей главе. Со-
ответственно, и ядро

+-----------------------------+ +-----------------------------+
| +------------+ | | +------------+ |
| | Процессоры | | | | Процессоры | |
| +-----+------+ | | +-----+------+ |
| ----+-------+------+------- | | ----+-------+------+------- |
| +---+----+ +-------+------+ | | +---+----+ +-------+------+ |
| | Память | | Периферийные | | | | Память | | Периферийные | |
| | | | устройства | | | | | | устройства | |
| +--------+ +--------------+ +-++-+ +--------+ +--------------+ |
+-----------------------------+ ++ +-----------------------------+
|
+-------------+---------------+
| +------------+ |
| | Процессоры | |
| +-----+------+ |
| ----+-------+------+------- |
| +---+----+ +-------+------+ |
| | Память | | Периферийные | |
| | | | устройства | |
| +--------+ +--------------+ |
+-----------------------------+

Рисунок 13.1. Модель системы с распределенной архитектурой

381


системы на каждой машине функционирует независимо от внешних условий эксплу-
атации распределенной среды.
Распределенные системы, хорошо описанные в литературе, традиционно де-
лятся на следующие категории:
* периферийные системы, представляющие собой группы машин, отличающихся
ярковыраженной общностью и связанных с одной (обычно более крупной) ма-
шиной. Периферийные процессоры делят свою нагрузку с центральным процес-
сором и переадресовывают ему все обращения к операционной системе. Цель
периферийной системы состоит в увеличении общей производительности сети
и в предоставлении возможности выделения процессора одному процессу в
операционной среде UNIX. Система запускается как отдельный модуль; в от-
личие от других моделей распределенных систем, периферийные системы не
обладают реальной автономией, за исключением случаев, связанных с дис-
петчеризацией процессов и распределением локальной памяти.
* распределенные системы типа "Newcastle", позволяющие осуществлять дис-
танционную связь по именам удаленных файлов в библиотеке (название взято
из статьи "The Newcastle Connection" - см. [Brownbridge 82]). Удаленные
файлы имеют спецификацию (составное имя), которая в указании пути поиска
содержит специальные символы или дополнительную компоненту имени, пред-
шествующую корню файловой системы. Реализация этого метода не предпола-
гает внесения изменений в ядро системы, вследствие этого он более прост,
чем другие методы, рассматриваемые в этой главе, но менее гибок.
* абсолютно "прозрачные" распределенные системы, в которых для обращения к
файлам, расположенным на других машинах, достаточно указания их стандар-
тных составных имен; распознавание этих файлов как удаленных входит в
обязанности ядра. Маршруты поиска файлов, указанные в их составных име-
нах, пересекают машинные границы в точках монтирования, сколько бы таких
точек ни было сформировано при монтировании файловых систем на дисках.

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


    13.1 ПЕРИФЕРИЙНЫЕ ПРОЦЕССОРЫ



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

382

При инициализации системы на центральном процессоре ядро по линиям связи
загружает на каждом из периферийных процессоров локальную операционную сис-
тему. Любой выполняемый на периферии процесс связан с процессом-спутником,
принадлежащим центральному процессору (см. [Birrell 84]); когда процесс,
протекающий на периферийном процессоре, вызывает системную функцию, которая
нуждается в услугах исключительно центрального процессора, периферийный про-
цесс связывается со своим спутником и запрос поступает на обработку на цент-
ральный процессор. Процесс-спутник исполняет системную функцию и посылает
результаты обратно на периферийный процессор. Взаимоотношения периферийного
процесса со своим спутником похожи на отношения клиента и сервера, подробно
рассмотренные нами в главе 11: периферийный процесс выступает клиентом свое-
го спутника, поддерживающего функции работы с файловой системой. При этом
удаленный процесс-сервер имеет только одного клиента. В разделе 13.4 мы рас-
смотрим процессы-серверы, имеющие несколько клиентов.

Центральный процессор Периферийный процессор
+-----------------------------+ +-----------------------------+
| +------------+ | | +------------+ |
| | Процессоры | | | | Процессоры | |
| +-----+------+ | | +-----+------+ |
| ----+-------+------+------- | | ----+-------+-------------- |
| +---+----+ +-------+------+ | | +---+----+ |
| | Память | | Периферийные | | | | Память | |
| | | | устройства | | | | | |
| +--------+ +--------------+ +-++-+ +--------+ |
+-----------------------------+ ++ +-----------------------------+
|
+-------------+---------------+
| +------------+ |
Периферийный | | Процессоры | |
процессор | +-----+------+ |
| ----+-------+-------------- |
| +---+----+ |
| | Память | |
| | | |
| +--------+ |
+-----------------------------+

Рисунок 13.2. Конфигурация периферийной системы


Когда периферийный процесс вызывает системную функцию, которую можно об-
работать локально, ядру нет надобности посылать запрос процессу-спутнику.
Так, например, в целях получения дополнительной памяти процесс может вызвать
для локального исполнения функцию sbrk. Однако, если требуются услуги цент-
рального процессора, например, чтобы открыть файл, ядро кодирует информацию
о передаваемых вызванной функции параметрах и условиях выполнения процесса в
некое сообщение, посылаемое процессу-спутнику (Рисунок 13.3). Сообщение
включает в себя признак, из которого следует, что системная функция выполня-
ется процессом-спутником от имени клиента, передаваемые функции параметры и
данные о среде выполнения процесса (например, пользовательский и групповой
коды идентификации), которые для разных функций различны. Оставшаяся часть
сообщения представляет собой данные переменной длины (например, составное
имя файла или данные, предназначенные для записи функцией write).
Процесс-спутник ждет поступления запросов от периферийного процесса; при
получении запроса он декодирует сообщение, определяет тип системной функции,
исполняет ее и преобразует результаты в ответ, посылаемый периферийному про-
цессу. Ответ, помимо результатов выполнения системной функции, включает в
себя сообщение об

383

Формат сообщения
+----------------+----------+---------------+--------------------+
| Признак вызова |Параметры |Данные о среде | Составное имя |
| системной функ-|системной |выполнения про-|------- или ------|
| ции |функции |цесса | поток данных |
+----------------+----------+---------------+--------------------+

Ответ
+------------+-----------+---------+---------------------+
| Результаты | Сообщение | Номер | |
| выполнения | об ошибке | сигнала |---- Поток данных ---|
| системной | | | |
| функции | | | |
+------------+-----------+---------+---------------------+

Рисунок 13.3. Форматы сообщений


ошибке (если она имела место), номер сигнала и массив данных переменной дли-
ны, содержащий, например, информацию, прочитанную из файла. Периферийный
процесс приостанавливается до получения ответа, получив его, производит рас-
шифровку и передает результаты пользователю. Такова общая схема обработки
обращений к операционной системе; теперь перейдем к более детальному расс-
мотрению отдельных функций.
Для того, чтобы объяснить, каким образом работает периферийная система,
рассмотрим ряд функций: getppid, open, write, fork, exit и signal. Функция
getppid довольно проста, поскольку она связана с простыми формами запроса и
ответа, которыми обмениваются периферийный и центральный процессоры. Ядро на
периферийном процессоре формирует сообщение, имеющее признак, из которого
следует, что запрашиваемой функцией является функция getppid, и посылает
запрос центральному процессору. Процесс-спутник на центральном процессоре
читает сообщение с периферийного процессора, расшифровывает тип системной
функции, исполняет ее и получает идентификатор своего родителя. Затем он
формирует ответ и передает его периферийному процессу, находящемуся в состо-
янии ожидания на другом конце линии связи. Когда периферийный процессор по-
лучает ответ, он передает его процессу, вызвавшему системную функцию
getppid. Если же периферийный процесс хранит данные (такие, как идентифика-
тор процесса-родителя) в локальной памяти, ему вообще не придется связывать-
ся со своим спутником.
Если производится обращение к системной функции open, периферийный про-
цесс посылает своему спутнику соответствующее сообщение, которое включает
имя файла и другие параметры. В случае успеха процесс-спутник выделяет ин-
декс и точку входа в таблицу файлов, отводит запись в таблице пользователь-
ских дескрипторов файла в своем пространстве и возвращает дескриптор файла
периферийному процессу. Все это время на другом конце линии связи периферий-
ный процесс ждет ответа. У него в распоряжении нет никаких структур, которые
хранили бы информацию об открываемом файле; возвращаемый функцией open деск-
риптор представляет собой указатель на запись в таблице пользовательских
дескрипторов файла, принадлежащей процессу-спутнику. Результаты выполнения
функции показаны на Рисунке 13.4.
Если производится обращение к системной функции write, периферийный про-
цессор формирует сообщение, состоящее из признака функции write, дескриптора
файла и объема записываемых данных. Затем из пространства периферийного про-
цесса он по линии связи копирует данные процессу-спутнику. Процесс-спутник
расшифровывает полученное сообщение, читает данные из линии связи и записы-
вает их в соответствующий файл (в качестве указателя на индекс которого и
запись о котором в таблице файлов используется содержащийся в сообщении дес-
криптор); все указанные действия выполняются на центральном процессоре. По


384

Центральный процессор Периферийный процессор
+--------------------------------------+ +---------------------+
| таблица | | |
| пользо- | | |
| ватель- | | |
| ских | | |
| дескрип- | | |
| таблица таблица торов | | |
| индексов файлов файла +--------+| | +---------+ |
| +-----+ +-----+ +-----+ |Процесс-|----------| Процесс | |
| | | | | | | |спутник || | +---------+ |
| +-----+ +-----+ +-----+ +-+------+| | |
| | -+-+ | | ++- -+---+ | | |
| +-----+ | +-----+ |+-----+ дескрип- | | |
| | | +-+- -+-+| | тор файла | | |
| +-----+ +-----+ +-----+ | | |
| | | | | | | |
| +-----+ +-----+ | | |
| | | | | | | |
| +-----+ +-----+ | | |
+--------------------------------------+ +---------------------+

Рисунок 13.4. Вызов функции open из периферийного процесса


окончании работы процесс-спутник передает периферийному процессу посылку,
подтверждающую прием сообщения и содержащую количество байт данных, успешно
переписанных в файл. Операция read выполняется аналогично; спутник информи-
рует периферийный процесс о количестве реально прочитанных байт (в случае
чтения данных с терминала или из канала это количество не всегда совпадает с
количеством, указанным в запросе). Для выполнения как той, так и другой фун-
кции может потребоваться многократная пересылка информационных сообщений по
сети, что определяется объемом пересылаемых данных и размерами сетевых паке-
тов.
Единственной функцией, требующей внесения изменений при работе на цент-
ральном процессоре, является системная функция fork. Когда процесс исполняет
эту функцию на ЦП, ядро выбирает для него периферийный процессор и посылает
сообщение специальному процессу -серверу, информируя последний о том, что
собирается приступить к выгрузке текущего процесса. Предполагая, что сервер
принял запрос, ядро с помощью функции fork создает новый периферийный про-
цесс, выделяя запись в таблице процессов и адресное пространство. Централь-
ный процессор выгружает копию процесса, вызвавшего функцию fork, на перифе-
рийный процессор, затирая только что выделенное адресное пространство, по-
рождает локальный спутник для связи с новым периферийным процессом и посыла-
ет на периферию сообщение о необходимости инициализации счетчика команд для
нового процесса. Процесс-спутник (на ЦП) является потомком процесса, вызвав-
шего функцию fork; периферийный процесс с технической точки зрения выступает
потомком процесса-сервера, но по логике он является потомком процесса, выз-
вавшего функцию fork. Процесс-сервер не имеет логической связи с потомком по
завершении функции fork; единственная задача сервера состоит в оказании по-
мощи при выгрузке потомка. Из-за сильной связи между компонентами системы
(периферийные процессоры не располагают автономией) периферийный процесс и
процесс-спутник имеют один и тот же код идентификации. Взаимосвязь между
процессами показана на Рисунке 13.5: непрерывной линией показана связь типа
"родитель-потомок", пунктиром - связь между равноправными партнерами.
Когда процесс исполняет функцию fork на периферийном процессоре, он по-
сылает сообщение своему спутнику на ЦП, который и исполняет после этого всю
вышеописанную последовательность действий. Спутник выбирает новый периферий-


385

Центральный процессор Периферийный процессор
+----------------------+ +----------------------+
| +------------------+ | | +------------------+ |
| | Процесс-родитель |-------------| Процесс-сервер | |
| +---------+--------+ | | +------------------+ |
| | | | |
| | | | |
| +---------+--------+ | | +------------------+ |
| | Порожденный спут-|-------------| Порожденный про- | |
| | ник | | | | цесс | |
| +------------------+ | | +------------------+ |
+----------------------+ +----------------------+

Рисунок 13.5. Выполнение функции fork на центральном процессоре


ный процессор и делает необходимые приготовления к выгрузке образа старого
процесса: посылает периферийному процессу-родителю запрос на чтение его об-
раза, в ответ на который на другом конце канала связи начинается передача
запрашиваемых данных. Спутник считывает передаваемый образ и переписывает
его периферийному потомку. Когда выгрузка образа заканчивается, про-
цесс-спутник исполняет функцию fork, создавая своего потомка на ЦП, и пере-
дает значение счетчика команд периферийному потомку, чтобы последний знал, с
какого адреса начинать выполнение. Очевидно, было бы лучше, если бы потомок
процесса-спутника назначался периферийному потомку в качестве родителя, од-
нако в нашем случае порожденные процессы получают возможность выполняться и
на других периферийных процессорах, а не только на том, на котором они соз-
даны. Взаимосвязь между процессами по завершении функции fork показана на
Рисунке 13.6. Когда периферийный процесс завершает свою работу, он посылает
соответствующее сообщение процессу-спутнику и тот тоже завершается. От про-
цесса-спутника инициатива завершения работы исходить не может.

Центральный процессор
+-------------------------------------------------------+
| +------------------+ +-----------------+ |
| | Спутник-родитель +----------+ Спутник-потомок | |
| +------------------+ +-----------------+ |
| - - |
+-------------------------------------------------------+
- -
+---------------------------+ +---------------------------+
| - | | - |
| +-----------------------+ | | +----------------------+ |
| | Периферийный родитель | | | | Периферийный потомок | |
| +-----------------------+ | | +----------------------+ |
+---------------------------+ +---------------------------+
Периферийный процессор Периферийный процессор

Рисунок 13.6. Выполнение функции fork на периферийном процессоре


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

386

полнение функции аварийно, процессу-спутнику в многопроцессорной системе
следует вести себя тем же образом. То же самое можно сказать и о том случае,
когда сигнал побуждает процесс к завершению своей работы с помощью функции
exit: периферийный процесс завершается и посылает соответствующее сообщение
процессу-спутнику, который, разумеется, тоже завершается.
Когда периферийный процесс вызывает системную функцию signal, он сохра-
няет текущую информацию в локальных таблицах и посылает сообщение своему
спутнику, информируя его о том, следует ли указанный сигнал принимать или же
игнорировать. Процессу-спутнику безразлично, выполнять ли перехват сигнала
или действие по умолчанию. Реакция процесса на сигнал зависит от трех факто-
ров (Рисунок 13.7): поступает ли сигнал во время выполнения процессом сис-
темной функции, сделано ли с помощью функции signal указание об игнорирова-
нии сигнала, возникает ли сигнал на этом же периферийном процессоре или на

+------------------------------------------------------------+
| алгоритм sighandle /* алгоритм обработки сигналов */ |
| входная информация: отсутствует |
| выходная информация: отсутствует |
| { |
| если (текущий процесс является чьим-то спутником или |
| имеет прототипа) |
| { |
| если (сигнал игнорируется) |
| вернуть управление; |
| если (сигнал поступил во время выполнения системной |
| функции) |
| поставить сигнал перед процессом-спутником; |
| в противном случае |
| послать сообщение о сигнале периферийному процес-|
| су; |
| } |
| в противном случае /* периферийный процесс */ |
| { |
| /* поступил ли сигнал во время выполнения системной |
| * функции или нет |
| */ |
| послать сигнал процессу-спутнику; |
| } |
| } |
| |
| алгоритм satellite_end_of_syscall /* завершение систем- |
| * ной функции, выз- |
| * ванной периферийным|
| * процессом */ |
| входная информация: отсутствует |
| выходная информация: отсутствует |
| { |
| если (во время выполнения системной функции поступило |
| прерывание) |
| послать периферийному процессу сообщение о прерыва- |
| нии, сигнал; |
| в противном случае /* выполнение системной функции не|
| * прерывалось */ |
| послать ответ: включить флаг, показывающий поступле- |
| ние сигнала; |
| } |
+------------------------------------------------------------+

Рисунок 13.7. Обработка сигналов в периферийной системе

387



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

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


Периферийный процесс Процесс-спутник
+------------------------------------------------------------
| Вызывает системную функцию read -
| Посылает сообщение о вызове функции -
| процессу-спутнику -
| Приостанавливается до получения -
| ответа от процесса-спутника Получает сообщение о
| - вызове системной функ-
| - ции read
| - Читает данные с тер-
| - минала
| - Приостанавливается в
| - ожидании получения
| - порции данных
| - -
| - -
| - Сигнал (пользователь
| - нажал клавишу "break")
| - Выходит из состояния
| - приостанова
| - Прекращает выполнение