16 /* подготовка аргументов и указателя на результат */
17 ival = atol(argv[2]);
18 arg.data_ptr = (char*)&ival; /* аргументы */
19 arg.data_size = sizeof(long); /* размер аргументов */
20 arg.desc_ptr = NULL;
21 arg.desc_num = 0;
22 arg.rbuf = (char*)&oval; /*
данные */
23 arg.rsize = sizeof(long); /* размер данных */
24 Signal(SIGCHLD, sig_chld);
25 if (Fork == 0) {
26 sleep(2); /* дочерний процесс */
27 exit(0); /* отправка SIGCHLD */
28 }
29 /* вызов процедуры сервера и вывод результата */
30 Door_call(fd, &arg);
31 printf(result: %ld\n", oval);
32 exit(0);
33 }
Клиенту будет возвращена та же ошибка, что и при досрочном завершении сервера — EINTR:
solaris % clientintr2 /tmp/door2 22
door_call error: interrupted system call
Поэтому нужно блокировать все сигналы, которые могут прервать вызов door_call.
Идемпотентные и неидемпотентные процедуры
А что произойдет, если мы перехватим сигнал EINTR и вызовем процедуру сервера еще раз, поскольку мы знаем, что эта ошибка возникла из-за нашего собственного прерывания системного вызова перехваченным сигналом (SIGCHLD)? Это может привести к некоторым проблемам, как мы покажем ниже.
Изменим сервер так, чтобы он выводил идентификатор вызванного потока, делал паузу в 6 секунд и выводил идентификатор потока по завершении его. В листинге 15.23 приведен текст новой процедуры сервера.
Листинг 15.23. Процедура сервера, выводящая свой идентификатор потока дважды