Троан Эрик В.
Шрифт:
Последним системным вызовом
epoll
является epoll_wait
, который блокирует до тех пор, пока один или несколько контролируемых файловых дескрипторов не будут иметь данные для чтения или же не будут готовы к записи. Первым аргументом является дескриптор epoll
, а последний — тайм-аутом в секундах. Если файловые дескрипторы не готовы к обработке до истечения тайм-аута, epoll_wait
возвращает 0
. Два промежуточных параметра определяют буфер для ядра, в который можно копировать структуры
struct epoll_event
. Параметр events
указывает на буфер, maxevents
определяет, какое количество структур struct epoll_event
помещается в буфер, а возвращаемое значение сообщает программе количество структур, помещенных в этот буфер (пока вызов не попадет в состояние тайм-аута либо не произойдет ошибка). Каждый системный вызов
struct epoll_event
сообщает программе полное состояние контролируемого файлового дескриптора. Элемент events
может иметь установленные флаги EPOLLIN
, EPOLLOUT
или EPOLLPRI
, а также два новых флага, которые описаны ниже. EPOLLERR | С файлом связано ожидающее состояние ошибки; это случается, если ошибка происходит в сокете, когда приложение не считывает из него или не записывает в него. |
EPOLLHUP | Файловый дескриптор завис; в главе 10 дана информация о том, когда это обычно происходит. |
На первый взгляд это все может показаться сложным, но на самом деле это очень похоже на работу
poll
. Вызов epoll_create
— это то же, что и распределение массива struct pollfd
, a epoll_ctl
— это то же, что и инициализация элементов этого массива. Главный цикл, обрабатывающий файловые дескрипторы, использует epoll_wait
вместо системного вызова poll
, а close
аналогичен освобождению памяти, занимаемой массивом struct pollfd
. Эти параллели помогают переписывать с применением epoll
программы мультиплексирования, которые изначально были реализованы с помощью poll
или select
. Интерфейс
epoll
предлагает еще одну возможность, которую невозможно сравнить с poll
или select
. Поскольку дескриптор epoll
в действительности является файловым дескриптором (вот почему его можно передавать close
), имеется возможность контролировать дескриптор epoll
как часть еще одного дескриптора epoll
либо через poll
или select
. Дескриптор epoll
будет готов к чтению из любого места, а вызов epoll_wait
вернет события. В окончательном решении проблемы мультиплексирования каналов, предложенном в данном разделе, используется
epoll
. Оно очень похоже на другие примеры, вот только определенная часть кода инициализации перемещена в новую функцию addEvent
для предотвращения нежелательного удлинения программы. 1: /* mpx-epoll.c */
2:
3: #include <fcntl.h>
4: #include <stdio.h>
5: #include <stdlib.h>
6: #include <sys/epoll.h>
7: #include <unistd.h>
8:
9: #include <sys/poll.h>
10:
11: void addEvent(int epfd, char * filename) {
12: int fd;
13: struct epoll_event event;
14:
15: if ((fd = open (filename, O_RDONLY | O_NONBLOCK)) < 0) {
16: perror("open");
17: exit(1);
18: }
19:
20: event.events = EPOLLIN;
21: event.data.fd = fd;
22:
23: if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event)) {
24: perror("epoll_ctl(ADD)");
25: exit(1);
26: }
27: }
28:
29: int main(void) {
30: char buf[4096];
31: int i, rc;
32: int epfd;
33: struct epoll_event events[2];
34: int num;
35: int numFds;
36:
37: epfd = epoll_create(2);
38: if (epfd < 0) {
39: perror("epoll_create");
40: return 1;
41: }
42:
43: /* открыть оба канала и добавить их в набор epoll */