Читать «UNIX: взаимодействие процессов» онлайн - страница 246

Уильям Ричард Стивенс

7   door_desc_t *descptr, size_t ndesc)

8  {

9   squareproc_in_t in;

10  squareproc_out_t out;

11  memcpy(&in, dataptr, min(sizeof(in), datasize));

12  printf("squareproc: thread id %ld, arg = %ld\n",

13   pr_thread_id(NULL), in.arg1);

14  sleep(5);

15  out.res1 = in.arg1 * in.arg1;

16  Door_return((char *) &out, sizeof(out), NULL, 0);

17 }

18 void

19 sqrtproc(void *cookie, char *dataptr, size_t datasize,

20  door_desc_t *descptr, size_t ndesc)

21 {

22  sqrtproc_in_t in;

23  sqrtproc_out_t out;

24  memcpy(&in, dataptr, min(sizeof(in), datasize));

25  printf("sqrtproc: thread id %ld, arg = %ld\n",

26   pr_thread_id(NULL), in.arg1);

27  sleep(5);

28  out.res1 = sqrt((double)in.arg1);

29  Door_return((char *) &out, sizeof(out), NULL, 0);

30 }

Функция main сервера, текст которой приведен в листинге 15.12, открывает дескрипторы дверей и связывает каждый из них с одной из процедур сервера.

Листинг 15.12. Функция main сервера

//doors/server7.c

31 int

32 main(int argc, char **argv)

33 {

34  int fd;

35  if (argc != 1)

36   err_quit("usage: server7");

37  fd = Door_create(squareproc, NULL, 0);

38  unlink(PATH_SQUARE_DOOR);

39  Close(Open(PATH_SQUARE_DOOR, O_CREAT | O_RDWR, FILE_MODE));

40  Fattach(fd, PATH_SQUARE_DOOR);

41  fd = Door_create(sqrtproc, NULL, 0);

42  unlink(PATH_SQRT_DOOR);

43  Close(Open(PATH_SQRT_DOOR, O_CREAT | O_RDWR, FILE_MODE));

44  Fattach(fd, PATH_SQRT_DOOR);

45  for (;;)

46   pause();

47 }

Запустим программу-клиент и подождем 10 секунд до вывода результатов (как мы и ожидали):

solaris % client7 77

result: 5929 8.77496

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

solaris % server7

squareproc: thread id 4, arg = 77

sqrtproc: thread id 4, arg = 77

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

Атрибут DOOR_UNREF для серверов

В разделе 15.3 мы отметили, что при вызове door_create для создаваемой двери можно указать атрибут DOOR_UNREF. В документации говорится, что если количество дескрипторов, относящихся к этой двери, уменьшается с двух до одного, осуществляется специальный вызов процедуры сервера. Особенность вызова заключается в том, что второй аргумент процедуры сервера (указатель на данные) при этом является константой DOOR_UNREF_DATA. Мы продемонстрируем три способа обращения к двери.

1. Дескриптор, возвращаемый door_create, считается первой ссылкой на эту дверь. Вообще говоря, причина, по которой специальный вызов происходит при изменении количества дескрипторов с 2 на 1, а не с 1 на 0, заключается в том, что первый дескриптор обычно не закрывается сервером до завершения работы.

2. Полное имя, связанное с дверью в файловой системе, также считается ссылкой на дверь. Ее можно удалить вызовом функции fdetach, или запустив программу fdetach, или удалив полное имя из файловой системы (функцией unlink или командой rm).

3.  Дескриптор, возвращаемый клиенту функцией open, считается открытой ссылкой до тех пор, пока не будет закрыт либо явным вызовом close, либо неявно, при завершении клиента. Во всех примерах этой главы дескриптор закрывается неявно.