• Открывает для ввода каждый файл, указанный в командной строке
• Входит в цикл
• После вызова epoll_wait() программа проверяет наличие ошибки EINTR
• Если вызов epoll_wait() завершается успешно, программа входит в еще один цикл, чтобы проверить готовность каждого элемента в списке evlist
• Цикл завершается при закрытии всех дескрипторов открытых файлов (то есть когда переменная numOpenFds равна 0).
Пример использования программы из листинга 59.5 приводится в следующих сессиях командной строки. Мы применяем два терминала. В первом наша программа отслеживает ввод в двух очередях FIFO (каждая из них открывается для чтения и будет закрыта только тогда, когда другой ее конец будет открыт для записи другим процессом; см. раздел 44.7). Во втором терминале запускаем несколько экземпляров команды cat(1), которые записывают данные в ранее упомянутые очереди FIFO.
Terminal window 1 Terminal window 2
$ mkfifo p q
$ ./epoll_input p q
$ cat > p
Opened "p" on fd 4
[1]+ Stopped cat >p
$ cat > q
Opened "q" on fd 5
About to epoll_wait()
[1]+ Stopped./epoll_input p q
Выше мы приостановили нашу программу мониторинга для получения возможности сгенерировать ввод для очередей FIFO и закрыть записывающий конец одной из них:
qqq
$ fg %1
cat >p
ppp
Теперь мы возобновляем нашу программу мониторинга, переводя ее в активный режим. После этого вызов epoll_wait() возвращает два события:
$ fg
./epoll_input p q
About to epoll_wait()
Ready: 2
fd=4; events: EPOLLIN
read 4 bytes: ppp
fd=5; events: EPOLLIN EPOLLHUP
read 4 bytes: qqq
closing fd 5
About to epoll_wait()
Две пустые строки в вышеприведенном выводе являются символами новой строки, которые были прочитаны экземплярами cat, записаны в очереди FIFO, а затем прочитаны и выведены нашей программой.
Далее мы нажимаем Ctrl+D во втором терминале, чтобы завершить оставшийся экземпляр cat; это опять приводит к завершению вызова epoll_wait(), который теперь возвращает всего одно событие:
Ready: 1
fd=4; events: EPOLLHUP
closing fd 4
All file descriptors closed; bye
Листинг 59.5. Использование программного интерфейса epoll
altio/epoll_input.c
#include
#include
#include "tlpi_hdr.h"
#define MAX_BUF 1000 /* Максимальный объем данных, получаемых за одно чтение */
#define MAX_EVENTS 5 /* Максимальное количество событий,
возвращаемых одним вызовом epoll_wait() */
int
main(int argc, char *argv[])
{
int epfd, ready, fd, s, j, numOpenFds;
struct epoll_event ev;
struct epoll_event evlist[MAX_EVENTS];
char buf[MAX_BUF];
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s file…\n", argv[0]);
if (epfd == -1)
errExit("epoll_create");
/* Открываем каждый файл в командной строке и добавляем его
в «список интереса» экземпляра epoll */
fd = open(argv[j], O_RDONLY);
if (fd == -1)
errExit("open");
printf("Opened \"%s\" on fd %d\n", argv[j], fd);
ev.events = EPOLLIN; /* Нас интересуют только события ввода */
ev.data.fd = fd;
errExit("epoll_ctl");
}
numOpenFds = argc — 1;
/* Извлекаем элемент из списка готовности (максимум MAX_EVENTS) */
printf("About to epoll_wait()\n");
if (ready == -1) {
continue;
/* Перезапускаем, если операция была прервана сигналом */
else
errExit("epoll_wait");
}
printf("Ready: %d\n", ready);
/* Обрабатываем полученный список событий */