15.2. Функция door_call

15.2. Функция door_call

Функция door_call вызывается клиентом для обращения к процедуре сервера, выполняемой в адресном пространстве процесса-сервера:

#include <door.h>

int door_call(int fd, door_arg_t *argp);

/* Возвращает 0 в случае успешного завершения. –1 – в случае ошибки */

Дескриптор fd обычно возвращается функцией open (см. листинг 15.1). Полное имя файла, открываемого клиентом, однозначно идентифицирует процедуру сервера, которая вызывается door_call при передаче дескриптора.

Второй аргумент — argp — указывает на структуру, описывающую аргументы и приемный буфер для возвращаемых значений:

typedef struct door_arg {

 char *data_ptr; /* при вызове указывает на аргументы, при возврате – на результаты */

 size_t data_size; /* при вызове определяет общий размер аргументов в байтах, при возврате – общий размер возвращаемых данных в байтах */

 door_desc_t *desc_ptr; /* при вызове указывает на аргументы-дескрипторы, при возврате указывает на возвращаемые дескрипторы */

 size_t desc_num; /* при вызове задает количество аргументов-дескрипторов, при возврате задает количество возвращаемых дескрипторов */

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

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

} door_arg_t;

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

ПРИМЕЧАНИЕ

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

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

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

ПРИМЕЧАНИЕ

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

? Аргументы-дескрипторы хранятся в массиве структур door_desc_t, каждая из которых содержит один передаваемый от клиента серверу дескриптор. Количество структур типа door_desc_t задается аргументом desc_num. (Мы описываем эту структуру и смысл «передачи дескриптора» в разделе 15.8.) Если аргументов-дескрипторов нет, следует передать нулевой указатель desc_ptr и присвоить полю desc_num значение 0.

? При возврате из функции data_ptr указывает на результаты-данные, a data_size задает размер возвращаемых данных. Если никакие данные не возвращаются, data_size будет иметь значение 0, а значение указателя data_ptr следует игнорировать.

? Функция может возвращать и дескрипторы, при этом desc_ptr указывает на массив структур типа door_desc_t, каждая из которых содержит один передаваемый сервером клиенту дескриптор. Количество возвращаемых структур типа door_desc_t хранится в поле desc_num. Если дескрипторы не возвращаются, значение desc_num будет равно 0, а указатель desc_ptr следует игнорировать.

Можно спокойно использовать один и тот же буфер для передаваемых аргументов и возвращаемых результатов. При вызове door_call и data_ptr, и desc_ptr могут указывать на буфер, указанный аргументом rbuf.

Перед вызовом door_call клиент устанавливает указатель rbuf на буфер для результатов, a rsize делает равным размеру буфера. После возвращения из функции и data_ptr, и desc_ptr будут указывать на этот буфер. Если он слишком мал для хранения результатов, возвращаемых сервером, библиотека дверей автоматически выделит новый буфер в адресном пространстве клиента с помощью mmap (раздел 12.2) и обновит значения rbuf и rsize соответствующим образом. Поля data_ptr и desc_ptr будут указывать на новый буфер. Клиент отвечает за то, чтобы обнаружить изменение этих указателей и впоследствии освободить занимаемую память вызовом munmap с аргументами rbuf и rsize. Пример будет приведен в листинге 15.4.

Данный текст является ознакомительным фрагментом.