Литмир - Электронная Библиотека
Содержание  
A
A
Значение flags Описание Изменяется Возвращается
EV_ADD Добавить новое событие, подразумевается по умолчанию, если не указан флаг EV_DISABLE
EV_CLEAR Сброс состояния события после считывания его пользователем
EV_DELETE Удаление события из фильтра
EV_DISABLE Отключение события без удаления его из фильтра
EV_ENABLE Включение отключенного перед этим события
EV_ONESHOT Удаление события после его однократного срабатывания
EV_EOF Достигнут конец файла
EV_ERROR Произошла ошибка, код errno записан в поле data

Типы фильтров приведены в табл. 14.6.

Таблица 14.6. Типы фильтров

Значение filter Описание
EVFILT_AIO События асинхронного ввода-вывода
EVFILT_PROC События exit, fork, exec для процесса
EVFILT_READ Дескриптор готов для чтения (аналогично select)
EVFILT_SIGNAL Описание сигнала
EVFILT_TIMER Периодические или одноразовые таймеры
EVFILT_VNODE Изменение и удаление файлов
EVFILT_WRITE Дескриптор готов для записи (аналогично select)

Перепишем функцию

str_cli
из листинга 6.2 так, чтобы она использовала
kqueue
. Результат представлен в листинге 14.8.

Листинг 14.8. Функция str_cli, использующая kqueue

//advio/str_cli_kqueue04.c

 1 #include "unp.h"

 2 void

 3 str_cli(FILE *fp, int sockfd)

 4 {

 5  int kq, i, n, nev, stdineof = 0, isfile;

 6  char buf[MAXLINE];

 7  struct kevent kev[2];

 8  struct timespec ts;

 9  struct stat st;

10  isfile = ((fstat(fileno(fp), &st) 0) &&

11   (st.st_mode & S_IFMT) == S_IFREG);

12  EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL);

13  EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);

14  kq = Kqueue();

15  ts.tv_sec = ts.tv_nsec = 0;

16  Kevent(kq, kev, 2, NULL, 0, &ts);

17  for (;;) {

18   nev = Kevent(kq, NULL, 0, kev, 2, NULL);

19   for (i = 0; i < nev; i++) {

20    if (kev[i].ident == sockfd) { /* сокет готов для чтения */

21     if ((n = Read(sockfd, buf, MAXLINE)) == 0) {

22      if (stdineof == 1)

23       return; /* нормальное завершение*/

24      else

25       err_quit("str_cli: server terminated prematurely");

26     }

27     Write(fileno(stdout), buf, n);

28    }

29    if (kev[i].ident == fileno(fp)) { /* входной поток готов к чтению */

30     n = Read(fileno(fp), buf, MAXLINE);

31     if (n > 0)

32      Writen(sockfd, buf, n);

33     if (n == 0 || (isfile && n == kev[i].data)) {

34      stdineof = 1;

35      Shutdown(sockfd, SHUT_WR); /* отправка FIN */

36      kev[i].flags = EV_DELETE;

37      Kevent(kq, &kev[i], 1, NULL, 0, &ts); /* удаление

                                                 kevent */

38      continue;

39     }

40    }

41   }

42  }

43 }

Проверка, указывает ли дескриптор на файл

10-11
 Поведение
kqueue
при достижении конца файла зависит от того, связан ли данный дескриптор с файлом, каналом или терминалом, поэтому мы вызываем
fstat
, чтобы убедиться, что мы работаем с файлом. Эти сведения понадобятся позже.

Настройка структур kevent для kqueue

12-13
 При помощи макроса
EV_SET
мы настраиваем две структуры
kevent
. Обе содержат фильтр событий готовности к чтению (
EVFILT_READ
) и запрос на добавление этого события к фильтру (
EV_ADD
).

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