Литмир - Электронная Библиотека
Содержание  
A
A

recvfrom_alarm(int signo) {

 had_alarm = 1;

 return;

}

Флаг сбрасывается в 0 каждый раз, когда вызывается функция

alarm
. Наша функция
dg_cli
проверяет этот флаг перед вызовом функции
recvfrom
и не вызывает ее, если флаг ненулевой.

for (;;) {

 len = servlen;

 Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL);

 if (had_alarm == 1)

  break;

 n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);

Если сигнал был сгенерирован во время его блокирования (после предыдущего возвращения из функции

recvfrom
), то после разблокирования в этой части кода он будет доставлен перед завершением функции
sigprocmask
, устанавливающей наш флаг. Однако между проверкой флага и вызовом функции
recvfrom
существует промежуток времени, в течение которого сигнал может быть сгенерирован и доставлен, и если это произойдет, вызов функции
recvfrom
заблокируется навсегда (разумеется, мы считаем при этом, что не приходит никаких дополнительных ответов).

Блокирование и разблокирование сигнала с помощью функции pselect

Одним из корректных решений будет использование функции

pselect
(см. раздел 6.9), как показано в листинге 20.3.

Листинг 20.3. Блокирование и разблокирование сигналов с помощью функции pselect

//bcast/dgclibcast4.с

 1 #include "unp.h"

 2 static void recvfrom_alarm(int);

 3 void

 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

 5 {

 6  int n;

 7  const int on = 1;

 8  char sendline[MAXLINE], recvline[MAXLINE + 1];

 9  fd_set rset;

10  sigset_t sigset_alrm, sigset_empty;

11  socklen_t len;

12  struct sockaddr *preply_addr;

13  preply_addr = Malloc(servlen);

14  Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

15  FD_ZERO(&rset);

16  Sigemptyset(&sigset_empty);

17  Sigemptyset(&sigset_alrm);

18  Sigaddset(&sigset_alrm, SIGALRM);

19  Signal(SIGALRM, recvfrom_alarm);

20  while (Fgets(sendline, MAXLINE, fp) != NULL) {

21   Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

22   Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL);

23   alarm(5);

24   for (;;) {

25    FD_SET(sockfd, &rset);

26    n = pselect(sockfd + 1, &rset, NULL, NULL, NULL, &sigset_empty);

27    if (n < 0) {

28     if (errno == EINTR)

29      break;

30     else

31      err_sys("pselect error");

32    } else if (n != 1)

33    err_sys("pselect error; returned %d", n);

34    len = servlen;

35    n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);

36    recvline[n] = 0; /* завершающий нуль */

37    printf("from %s: %s",

38    Sock_ntop_host(preply_addr, len), recvline);

39   }

40  }

41  free(preply_addr);

42 }

43 static void

44 recvfrom_alarm(int signo)

45 {

46  return; /* просто прерываем recvfrom() */

47 }

22-23
 Мы блокируем сигнал
SIGALRM
и вызываем функцию
pselect
. Последний аргумент этой функции — указатель на нашу переменную
sigset_empty
, являющуюся набором сигналов, в котором нет блокированных сигналов (все сигналы разблокированы). Функция
pselect
сохранит текущую маску сигналов (которая блокирует
SIGALRM
), проверит заданные дескрипторы, заблокируется при необходимости с маской сигналов, установленной в пустой набор, но перед завершением функции маска сигналов процесса будет переустановлена в исходное значение, которое она имела при вызове функции
pselect
. Ключ к пониманию функции
pselect
в том, что установка маски сигналов, проверка дескрипторов и переустановка маски сигнала — это атомарные операции по отношению к вызывающему процессу.

34-38
 Если наш сокет готов для чтения, мы вызываем функцию
recvfrom
, зная, что она не заблокируется.

Как мы упоминали в разделе 6.9, функция

pselect
— относительно новая среди других, описываемых спецификацией POSIX. Из всех систем, показанных на рис. 1.7, эту функцию поддерживают только FreeBSD и Linux. Тем не менее в листинге 20.4 представлена простая, хотя и некорректная ее реализация. Мы приводим ее здесь, несмотря на некорректность, чтобы продемонстрировать три стадии решения: установку маски сигнала в значение, заданное вызывающей функцией, с сохранением текущей маски, проверку дескрипторов и переустановку маски сигнала.

224
{"b":"225366","o":1}