Книга: UNIX: разработка сетевых приложений
Использование функций sigsetjmp и siglongjmp
Разделы на этой странице:
Использование функций sigsetjmp и siglongjmp
Нашу проблему можно решить корректно, если отказаться от прерывания блокированного системного вызова обработчиком сигнала, вместо этого вызвав из обработчика сигнала функцию siglongjmp
. Этот метод называется нелокальным оператором goto (nonlocal goto), поскольку мы можем использовать его для перехода из одной функции в другую. В листинге 20.5 проиллюстрирована эта технология.
Листинг 20.5. Вызов функций sigsetjmp и siglongjmp из обработчика сигнала
//bcast/dgclibcast5.c
1 #include "unp.h"
2 #include <setjmp.h>
3 static void recvfrom_alarm(int);
4 static sigjmp_buf jmpbuf;
5 void
6 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
7 {
8 int n;
9 const int on = 1;
10 char sendline[MAXLINE], recvline[MAXLINE + 1];
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 Signal(SIGALRM, recvfrom_alarm);
16 while (Fgets(sendline, MAXLINE, fp) != NULL) {
17 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
18 alarm(5);
19 for (;;) {
20 if (sigsetjmp(jmpbuf, 1) != 0)
21 break;
22 len = servlen;
23 n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
24 recvline[n] = 0; /* null terminate */
25 printf("from %s: %s",
26 Sock_ntop_host(preply_addr, len), recvline);
27 }
28 }
29 free(preply_addr);
30 }
31 static void
32 recvfrom_alarm(int signo)
33 {
34 siglongjmp(jmpbuf, 1);
35 }
Размещение буфера перехода в памяти
4
Мы выделяем буфер перехода, который будет использовать наша функция и ее обработчик сигнала.
Вызов функции sigsetjmp
20-23
Когда мы вызываем функцию sigsetjmp
непосредственно из нашей функции dg_cli
, она устанавливает буфер перехода и возвращает нуль. Мы продолжаем работать дальше и вызываем функцию recvfrom
.
Обработка сигнала SIGALRM и вызов функции siglongjmp
31-35
Когда сигнал доставлен, мы вызываем функцию siglongjmp
. Это заставляет sigsetjmp
в функции dg_cli
возвратить значение, равное второму аргументу (1), который должен быть ненулевым. Это приведет к завершению цикла for
в функции dg_cli
.
Использование функций sigsetjmp
и siglongjmp
подобным образом гарантирует, что мы не останемся навсегда блокированы в вызове функции recvfrom
из-за доставки сигнала в неподходящее время. Однако такое решение создает иную потенциальную проблему. Если сигнал доставляется в тот момент, когда функция printf
осуществляет вывод данных, управление будет передано из printf
обратно на sigsetjmp
. При этом в структурах данных printf
могут возникнуть противоречия. Чтобы предотвратить эту проблему, следует объединить блокирование и разблокирование сигналов, показанное в листинге 20.2, с помощью нелокального оператора goto
.
- Восстановление с использованием инструмента gbak
- Типы страниц и их использование
- Использование констант
- Использование переменной окружения ISC_PATH
- Использование сервера Yaffil внутри процесса
- Использование CAST() с типами дата
- Использование типов содержимого и столбцов
- Вызов хранимых процедур InterBase с использованием стандартного синтаксиса ODBC
- Использование кнопки Автосумма
- 24.7. Использование программы-твикера
- Использование отдельных процессоров XSLT
- 4. Использование подзапросов