Читать интересную книгу UNIX: взаимодействие процессов - Уильям Стивенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 85 86 87 88 89 90 91 92 93 ... 128

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

■ DOOR_PRIVATE — библиотека дверей автоматически создает новые потоки в процессе-сервере при поступлении запросов от клиентов. По умолчанию эти потоки помещаются в пул потоков и могут использоваться для обслуживания запросов клиентов по всем дверям данного процесса.

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

■ DOOR_UNREF — когда количество дескрипторов, открытых для данной двери, изменяется с двух до одного, процедура сервера вызывается со вторым аргументом, имеющим значение DOOR_UNREF_DATA. При этом аргумент descptr представляет собой нулевой указатель, а аргументы datasize и ndesc равны нулю. Мы приведем пример использования этого атрибута в листинге 15.13.

Возвращаемое сервером значение имеет тип void, поскольку процедура сервера никогда не завершает работу вызовом 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, и будет в них открыт.

ПРИМЕЧАНИЕ

Если мы учтем, что дверь идентифицируется с помощью PID и адреса процедуры сервера (что мы узнаем из структуры door_info_t в разделе 15.6), ограничения на вызовы exec и fork станут понятны. Дочерний процесс не будет принимать вызовов, поскольку его идентификатор процесса отличается от идентификатора, связанного с дверью. Дескриптор должен быть закрыт при вызове exec, потому что хотя идентификатор при этом и не меняется, адрес процедуры сервера уже не будет иметь никакого смысла в той программе, которая будет запущена после вызова exec.

15.4. Функция door_return

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

#include <door.h>

int door_return(char *dataptr, size_t datasize, door_desc_t *descptr, size_t ndesc);

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

Возвращаемые данные задаются аргументами dataptr и datasize, а возвращаемые дескрипторы — descptr и ndesc.

15.5. Функция door_cred

Интерфейс дверей предусматривает полезную возможность получения информации о клиенте при каждом вызове. Это осуществляется функцией door_cred:

#include <door.h>

int door_cred(door_cred_t *cred);

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

Структура, на которую указывает аргумент cred, имеет тип door_cred_t, определяемый как

typedef struct door_cred {

 uid_t dc_euid; /* действующий идентификатор пользователя клиента */

 gid_t dc_egid; /* действующий идентификатор группы клиента */

 uid_t dc_ruid; /* реальный идентификатор пользователя клиента */

 gid_t dc_rgid; /* реальный идентификатор группы клиента */

 pid_t dc_pid; /* идентификатор процесса клиента */

} door_cred_t;

В эту структуру помещается информация о клиенте при возвращении из вызова door_cred. В разделе 4.4 [21] подробно рассказывается о различиях между действующими и реальными идентификаторами пользователя и группы, а пример использования этой функции приведен в листинге. 15.5.

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

15.6. Функция door_info

Только что описанная функция door_cred предоставляет серверу информацию о клиенте. Клиент же может получить информацию о сервере, вызвав doo_info:

#include <door.h>

int door_info(int fd, door_info_t *info);

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

Дескриптор fd указывает на открытую дверь. Структура типа door_info_t, на которую указывает info, после возвращения из функции содержит информацию о сервере:

typedef struct doo_info {

 pid_t di_target; /* идентификатор процесса сервера */

 door_ptr_t di_proc; /* процедура сервера */

 door_ptr_t di_data; /* принимаемые процедурой сервера данные */

 door_attr_t di_attributes; /* атрибуты, связанные с данной дверью */

 door_id_t di_uniquifier; /* уникальный номер двери */

} door info t;

Поле di_target содержит идентификатор процесса сервера, a di_proc — адрес процедуры сервера в процессе (от которого клиенту, вообще говоря, пользы мало). Указатель, передаваемый процедуре сервера в качестве первого аргумента (cookie), возвращается клиенту в поле di_data.

Текущие атрибуты двери помещаются в поле di_attributes, и два из них уже были описаны в разделе 15.3. Это атрибуты DOOR_PRIVATE и DOOR_UNREF. Два других атрибута называются DOOR_LOCAL (процедура является локальной для данного процесса) и DOOR_REVOKE (сервер аннулировал процедуру, связанную с этой дверью, вызвав door_revoke).

Каждой двери при создании сопоставляется уникальный в пределах системы номер, который возвращается в поле di_uniquifier.

Эта функция обычно вызывается клиентом для получения информации о сервере. Однако она может быть вызвана и из процедуры сервера, причем первым аргументом в этом случае должна быть константа DOOR_QUERY. Тогда функция возвратит информацию о вызвавшем потоке, то есть о данном экземпляре процедуры сервера. В этом случае адреса процедуры сервера и принимаемых аргументов (di_proc и di_data) могут представлять интерес.

15.7. Примеры

В этом разделе мы приведем примеры использования пяти только что описанных функций.

Функция door_info

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

Листинг 15.3. Вывод информации о двери

//doors/doorinfo.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   int fd;

6   struct stat stat;

7   struct door_info info;

8   if (argc != 2)

9    err_quit("usage; doorinfo <pathname>");

10  fd = Open(argv[1], O_RDONLY);

11  Fstat(fd, &stat);

12  if (S_ISDOOR(stat.st_mode) == 0)

13   err_quit("pathname is not a door");

14  Door_info(fd, &info);

15  printf("server PID = %ld, uniquifier = %ld",

16   (long)info.di_target, (long)info.di_uniquifier);

17  if (info.di_attributes & DOOR_LOCAL)

18   printf(", DOOR_LOCAL");

19  if (info.di_attributes & DOOR_PRIVATE)

20   printf(", DOOR_PRIVATE");

21  if (info.di_attributes & DOOR_REVOKED)

22   printf(", DOOR_REVOKED");

23  if (info.di_attributes & DOOR_UNREF)

24   printf(", DOOR_UNREF");

25  printf("n");

26  exit(0);

27 }

Сначала программа открывает файл с указанным полным именем и проверяет, что это действительно дверь. Поле st_mode структуры stat в этом случае должно содержать такое значение, что макрос S_ISDOOR будет возвращать значение «истина». Затем вызывается функция door_info.

Сначала мы укажем этой программе полное имя файла, не являющегося дверью, а затем попробуем получить информацию о двух встроенных дверях Solaris 2.6:

solaris % doorinfo/etc/passwd

pathname is not a door

solaris % doorinfo /etc/.name_service_door

server PID = 308, uniquifier = 18, DOOR_UNREF

solaris % doorinfo /etc/.syslog_door

server PID = 282, uniquifier = 1635

solaris % ps –f -p 308

root 308 1 0 Apr 01 ? 0:34 /usr/sbin/nscd

solaris % ps –f -p 282

1 ... 85 86 87 88 89 90 91 92 93 ... 128
На этом сайте Вы можете читать книги онлайн бесплатно русская версия UNIX: взаимодействие процессов - Уильям Стивенс.

Оставить комментарий