Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

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 представлена простая, хотя и некорректная ее реализация. Мы приводим ее здесь, несмотря на некорректность, чтобы продемонстрировать три стадии решения: установку маски сигнала в значение, заданное вызывающей функцией, с сохранением текущей маски, проверку дескрипторов и переустановку маски сигнала.

Листинг 20.4. Простая некорректная реализация функции pselect

//lib/pselect.c

9 #include "unp.h"

10 int

11 pselect(int nfds, fd_set *rset, fd_set *wset, fd_set *xset,

12 const struct timespec *ts, const sigset_t *sigmask)

13 {

14 int n;

15 struct timeval tv;

16 sigset_t savemask;

17 if (ts != NULL) {

18 tv.tv_sec = ts->tv_sec;

19 tv.tv_usec = ts->tv_nsec / 1000; /* наносекунды -> микросекунды */

20 }

21 sigprocmask(SIG_SETMASK, sigmask, &savemask); /* маска вызывающего

процесса */

22 n = select(nfds, rset, wset, xset., (ts == NULL) ? NULL : &tv);

23 sigprocmask(SIG_SETMASK, &savemask, NULL); /* восстанавливаем

исходную маску */

24 return (n);

25 }

Использование функций 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));

  • Читать дальше
  • 1
  • ...
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: