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, либо неявно, при завершении клиента. Во всех примерах этой главы дескриптор закрывается неявно.
Первый пример показывает, что если сервер закрывает свой дескриптор после вызова fattach, немедленно происходит специальный вызов процедуры сервера. В листинге 15.13 приведен текст процедуры сервера и функции main.
//doors/serverunref1.c
1 #include "unpipc.h"
2 void
3 servproc(void *cookie, char *dataptr, size_t datasize,
4 door_desc_t *descptr, size_t ndesc)
5 {
6 long arg, result;
7 if (dataptr == DOOR_UNREF_DATA) {
8 printf("door unreferenced\n");
9 Door_return(NULL, 0, NULL, 0);
10 }
11 arg = *((long*)dataptr);
12 printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
13 sleep(6);
14 result = arg * arg;
15 Door_return((char *)result, sizeof(result), NULL, 0);
16 }
17 int
18 main(int argc, char **argv)
19 {
20 int fd;
21 if (argc != 2)
22 err_quit("usage: server1 server-pathname");
23 /* создание дескриптора и связывание с файлом */
24 fd = Door_create(servproc, NULL, DOOR_UNREF);
25 unlink(argv[1]);
26 Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
27 Fattach(fd, argv[1]);
28 Close(fd);
29 /* процедура servproc обрабатывает все запросы клиентов */
30 for(;;)
31 pause;
32 }
7-10 Процедура сервера распознает специальный вызов и выводит сообщение об этом. Возврат из специального вызова происходит путем вызова door_return с двумя нулевыми указателями и нулевыми значениями размеров.