Книга: UNIX: взаимодействие процессов

Непрерываемость системного вызова door_call

Непрерываемость системного вызова door_call

Документация на door_call предупреждает, что эта функция не предполагает возможности перезапуска (библиотечная функция door_call делает системный вызов с тем же именем). Мы можем убедиться в этом, изменив процедуру сервера таким образом, чтобы она делала паузу в 6 секунд перед возвращением, что показано в листинге 15.21.

Листинг 15.21. Процедура сервера делает паузу в 6 секунд

//doors/serverintr2.с
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   sleep(6); /* клиент получает сигнал SIGCHLD */
8   arg = *((long*)dataptr);
9   result = arg * arg;
10  Door_return((char*)&result, sizeof(result), NULL, 0);
11 }

Изменим теперь клиент из листинга 15.2: установим обработчик сигнала SIGCHLD, добавив порождение процесса и завершение порожденного процесса через 2 секунды. Таким образом, через 2 секунды после вызова door_call дочерний процесс завершит работу, а родительский перехватит сигнал SIGCHLD и произойдет возврат из обработчика сигнала, прерывающий системный вызов door_call. Текст программы-клиента показан в листинге 15.22.

Листинг 15.22. Клиент, перехватывающий сигнал SIGCHLD

//doors/clientintr2.c
1  #include "unpipc.h"
2  void
3  sig_chld(int signo)
4  {
5   return; /* просто прерываем door_call() */
6  }
7  int
8  main(int argc, char **argv)
9  {
10  int fd;
11  long ival, oval;
12  door_arg_t arg;
13  if (argc != 3)
14   err_quit("usage: clientintr2 <server-pathname> <integer-value>");
15  fd = Open(argv[1], O_RDWR); /* открываем дверь */
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: %ldn", oval);
32  exit(0);
33 }

Клиенту будет возвращена та же ошибка, что и при досрочном завершении сервера — EINTR:

solaris % clientintr2 /tmp/door2 22
door_call error: interrupted system call

Поэтому нужно блокировать все сигналы, которые могут прервать вызов door_call.

Оглавление книги


Генерация: 1.508. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз