Главная страница  Взаимодействие нетривиальных процессов 

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

door desc t *desc ptr; /* при вызове указывает на аргументы-дескрипторы, при возврате указывает на возвращаемые дескрипторы */

size t desc nutti: /* при вызове задает количество аргументов-дескрипторов, при возврате задает количество возвращаемых дескрипторов */

char *rbuf; /* указатель на буфер результатов */

size t rsize; /* размер буфера результатов */

} door arg t;

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

ПРИМЕЧАНИЕ

Использование типа char * для двух указателей кажется странным и требует использования явного преобразования типов для предотвращения вывода предупреждений компилятора. Естественно было бы использовать указатели типа void *, С указателями cliar * мы еще столкнемся в функции door return. Вероятно, в Solaris 2,7 тип данных desc num изменится на unsigned int и последний аргумент door return изменится соответствующим образом,

Аргументы и результаты могут быть двух типов: данные и дескрипторы.

Аргументы-данные представляют собой последовательность данных длиной data size байт. На эту последовательность должен указывать data ptr. Клиент и сервер должны заранее знать формат этих данных (и аргументов, и результатов). Нет способа указать серверу тип аргументов. В программах листингов 15.1 и 15.2 клиент и сервер были написаны таким образом, что они оба знали, что аргумент представлял собой одно длинное целое и возвращаемый результат также был одним длинным целым. Для скрытия внутреннего устройства передаваемых данных их можно объединить в структуру, что упростит работу тому, кто будет читать код несколько лет спустя. Итак, все аргументы можно заключить в одну структуру, результаты - в другую и обе их определить в одном заголовочном файле, используемом клиентом и сервером. Пример будет приведен в листингах 15.8 и 15.9. Если аргументов-данных нет, указатель data ptr должен быть нулевым и размер данных data size должен иметь значение 0.

ПРИМЕЧАНИЕ

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

Аргументы-дескрипторы хранятся в массиве структур door desc t, каждая из которых содержит один передаваемый от клиента серверу дескриптор. Количество структур типа door desc t задается аргументом desc nuni. (Мы описываем эту структуру и смысл передачи дескриптора в разделе 15.8.) Если аргументов-дескрипторов нет, следует передать нулевой указатель desc ptr и присвоить полю desc nuni значение 0.

При возврате из функции data jDtr указывает на результаты-данные, а data si ze задает размер возвращаемых данных. Если никакие данные не возвращаются,



data size будет иметь значение О, а значение указателя data ptr следует игнорировать.

ii Функция может возвращать и дескрипторы, при этом descjDtr указывает на массив структур типа door desc t, каждая из которых содержит один передаваемый сервером клиенту дескриптор. Количество возвращаемых структур типа door desc t хранится в поле desc nuni. Если дескрипторы не возвращаются, значение desc nuni будет равно О, а указатель desc pt г следует игнорировать.

Можно спокойно использовать один и тот же буфер для передаваемых аргументов и возвращаемых результатов. При вызове door cal 1 и data ptr, и desc ptr могут указывать на буфер, указанный аргументом rbuf.

Перед вызовом door cal 1 клиент устанавливает указатель rbuf на буфер для результатов, а rsize делает равным размеру буфера. После возвращения из функции и data ptr, и descjDtr будзт указывать на этот буфер. Если он слишком мал для хранения результатов, возвращаемых сервером, библиотека дверей автоматически выделит новый буфер в адресном пространстве клиента с помощью ппар (раздел 12,2) и обновит значения rbuf и rsi ze соответствующим образом. Поля data ptr и desc ptr будут указывать на новый буфер. Клиент отвечает за то, чтобы обнаружить изменение этих указателей и впоследствии освободить занимаемую память вызовом munmap с аргументами rbuf и rsi ze. Пример будет приведен в листинге 15.4,

15.3. Функция door create

Процесс-сервер определяет некоторую функцию как процедуру сервера вызовом door create;

finclude <door.h>

typedef void Door server proc(void *cook1e. char *dataptr, size t datasize.

door desc t *descptr. size t ndesc): int door create(Door server proc *proc. void *cookie, u int attr): I* Возвращает неотрицательный дескриптор в случае успешного завершения, -1 -в случае ошибки */

Здесь мы добавили наше собственное определение типа, что упрощает прототип функции. Это определение утверждает, что процедуры сервера (например, servproc в листинге 15,2) вызываются с пятью арг) ентами и ничего не возвращают.

Когда сервер вызывает doorcreate, первый аргумент (ргос) указывает адрес процедуры сервера, которая будет вызываться через дескриптор двери, возвращаемый этим вызовом. При вызове процедуры сервера ее аргумент cookie содержит значение, передаваемое в качестве второго аргумента door create. Это дает серверу возможность передавать процедуре какой-либо указатель каждый раз, когда эта процедура вызывается клиентом. Следующих четыре аргумента процедуры сервера - dataptr, datasize, descptr и ndesc - описывают аргументы-данные и аргументы-дескрипторы клиента. Они соответствуют первым четырем полям структуры door arg t, описанной в предыдущем разделе.

Последний аргумент door create (attr) описывает специальные атрибуты процедуры сервера и может быть равен либо О, либо логической сумме двух констант:

я DOOR PRI VATE - библиотека дверей автоматически создает новые потоки в процессе-сервере при поступлении запросов от клиентов. По умолчанию эти по-



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

Указание атрибута DOOR PRIVATE говорит библиотеке, что для данной двери следует создать собственный пул потоков, отдельный от пула потоков процесса.

Ш DOORJJNREF - ковда количество дескрипторов, открытых для данной двери, изменяется с двух до одного, процедура сервера вызывается со вторым аргументом, имеющим значение DOOR UNREF DATA, При этом аргумент descptr представляет собой нулевой указатель, а аргументы datasize и ndesc равны нулю. Мы приведем пример использования этого атрибута в листинге 15.13,

Возвращаемое сервером значение имеет тип voi d, поскольку процедура сервера никогда не завершает работу вызовом return. Вместо этого процедура должна вызывать door return (функция описана в следующем разделе),

В листинге 15,2 мы видели, что после получения дескриптора двери вызовом door create сервер должен вызвать fattach для связывания этого дескриптора с некоторым файлом. Клиент затем может открыть этот файл для получения дескриптора двери, который впоследствии может быть использован при вызове door call,

ПРИМЕЧАНИЕ -

Функция fattach не включена в стандарт Posix. 1, но ее наличие требуется стандартом Unix 98, Кроме того, этот стандарт определяет также функцию fdetach, отключающую связь дескриптора и файла, и программу fdetach, вызывающую эту функцию.

Для дескрипторов дверей, создаваемых door create, устанавливается бит FD CLOEXEC, Это означает, что дескриптор закрывается при вызове процессом функций типа exec. Что касается вызова fork, несмотря на то что открытые родительским процессом дескрипторы используются дочерним процессом совместно с ним, только родительский процесс будет принимать вызовы от клиентов. Дочерним процессам вызовы не передаются, хотя дескриптор, возвращаемый door create, и будет в них открыт.

ПРИМЕЧАНИЕ

Если мы учтем, что дверь идентифицируется с помощью РШ и адреса процедуры сервера (что мы узнаем из структуры door info t в разделе 15,6), ограничения на вызовы exec и fork станут понятны. Дочерний процесс не будет принимать вызовов, поскольку его идентификатор процесса отличается от идентификатора, связанного с дверью. Дескриптор должен быть закрыт при вызове exec, потому что хотя идентификатор при этом и не меняется, адрес процедуры сервера уже не будет иметь никакого смысла в той программе, которая будет запущена после вызова exec.

15.4. Функция door return

После завершения работы процедуры сервера возврат из нее осуществляется вызовом door return. Это приводит к возврату из door cal 1 соответствующего клиента.



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

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