13 printf("setting shm size to %d\n", i);
14 Ftruncate(fd, i);
15 printf("ptr[%d] = %d\n", i-1, ptr[i-1]);
16 }
17 exit(0);
18 }
2. Одна из возможных проблем при использовании *ptr++ заключается в том, что указатель, возвращенный mmap, изменяется, что может помешать впоследствии вызвать munmap. Если этот указатель еще понадобится, лучше его сохранить или вовсе не изменять.
Глава 14
1. Нужно изменить только одну строку:
13с13
< id = Shmget(Ftok(argv[1], 0), 0, SVSHM_MORE);
…
> id = atol(argv[1]);
Глава 15
1. Аргументы будут иметь размер data_size + (desc_numxsizeof(door_desc_t)) байт.
2. Вызывать fstat не нужно. Если дескриптор не указывает на дверь, вызов door_infо возвращает ошибку EBADF:
solaris % doorinfo /etc/passwd
door_info error: Bad file number
3. Документация содержит неверные сведения. Стандарт Posix утверждает, что функция sleep приведет к приостановке вызвавшего
4. Результат непредсказуем (хотя, скорее всего, будет выполнен дамп памяти), поскольку адрес процедуры сервера, связанной с дверью, в новом процессе будет указывать на совершенно случайную область памяти.
5. При завершении door_call из-за перехвата сигнала сервер следует уведомить об этом, поскольку поток, работающий с этим клиентом, получит запрос на отмену выполнения. В связи с листингом 15.18 мы говорили, что отмена для создаваемых библиотекой потоков по умолчанию отключена, следовательно, поток завершен не будет. Вместо этого происходит досрочный возврат из вызова sleep(6) в процедуре сервера, но она продолжает выполняться.
6. Вот что мы увидим:
solaris % server6 /tmp/door6
my_thread: created sever thread 4
door_bind error: Bad file number
Запустив сервер 20 раз подряд, мы получим 5 сообщений об ошибке. Предсказать такую ошибку заранее нельзя.
7. Нет. Все, что нужно, — включать возможность отмены каждый раз при вызове процедуры сервера, как мы делали в листинге 15.26. Хотя в этом случае и приходится вызывать pthread_setcancelstate каждый раз при запуске процедуры сервера, накладные расходы, скорее всего, будут невелики.
8. Чтобы проверить это, изменим код одного из серверов (скажем, из листинга 15.6) так, чтобы он вызывал door_revoke из процедуры сервера. Поскольку аргументом door_revoke является дескриптор двери, его придется сделать глобальным. Вот что получится при запуске клиента (из листинга 15.1) два раза подряд:
solaris % client8 /tmp/door8 88
result: 7744
solaris % client8 /tmp/door8 99
door_call error: Bad file number
Первый вызов завершается успешно, что подтверждает наше предположение насчет door_revoke. Второй вызов возвращает ошибку EBADF.
9. Чтобы не делать дескриптор fd глобальным, мы воспользуемся указателем cookiе, который можем передать door_create и который затем будет передаваться процедуре сервера при каждом вызове. В листинге Г.10 приведен текст сервера.
//doors/server9.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 Door_revoke(*((int *) cookie));
8 arg = *((long *) dataptr);
9 printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
10 result = arg * arg;
11 Door_return((char *) &result, sizeof(result), NULL, 0);
12 }
13 int
14 main(int argc, char **argv)
15 {
16 int fd;
17 if (argc != 2)
18 err_quit("usage: server9
19 fd = Door_create(servproc, &fd, 0);
20 unlink(argv[1]);
21 Close(Open(argv[1], O_CREAT | O_RDWR, FILE MODE));
22 Fattach(fd, argv[1]);
23 for(;;)
24 pause();
25 }
Мы легко могли бы изменить листинги 5.17 и 5.18, поскольку указатель cookie доступен функции my_thread (через структуру door_info_t), которая передает указатель на эту структуру создаваемому потоку (которому нужно знать дескриптор для вызова door_bind).