Начиная с версии 2.6.27 ядро Linux поддерживает новый системный вызов epoll_create1(). Он выполняет те же действия, что и epoll_create(), но вместо устаревшего аргумента size принимает аргумент flags, с помощью которого можно влиять на поведение данного системного вызова. На сегодняшний день поддерживается всего одно значение, EPOLL_CLOEXEC, заставляющее ядро включить для нового файлового дескриптора флаг FD_CLOEXEC. Он может пригодиться по тем же причинам, что и флаг O_CLOEXEC для вызова open(), описанный в подразделе 4.3.1.
59.4.2. Редактирование списка интереса epoll: вызов epoll_ctl()
Системный вызов epoll_ctl() изменяет список интереса экземпляра epoll, на который ссылается файловый дескриптор epfd.
#include
int epoll_ctl(int
Возвращает 0 при успешном завершении или -1 при ошибке
Аргумент fd обозначает файловый дескриптор из списка интереса, параметры которого нужно изменить. Он может ссылаться на именованный канал, очередь FIFO, сокет, очередь сообщений POSIX, экземпляр inotify, терминал, устройство или даже другой дескриптор epoll (то есть можно сформировать некую иерархию отслеживаемых дескрипторов). Однако в качестве fd нельзя передать дескриптор обычного файла или каталога (в этом случае вызов завершается ошибкой EPERM).
Аргумент op обозначает операцию, которую нужно выполнить. Он может принимать одно из следующих значений.
• EPOLL_CTL_ADD — добавляет файловый дескриптор fd в список интереса экземпляра epfd. Набор событий, которые мы хотим отслеживать для этого дескриптора, задается в виде буфера, на какой указывает аргумент ev (см. ниже). При попытке добавления дескриптора, уже находящегося в списке интереса, вызов epoll_ctl() завершается ошибкой EEXIST.
• EPOLL_CTL_MOD — изменяет параметры событий для дескриптора fd, используя информацию в буфере, на который указывает аргумент ev. Если попытаться изменить параметры дескриптора, не входящего в список интереса, то вызов epoll_ctl() завершится ошибкой ENOENT.
• EPOLL_CTL_DEL — удаляет файловый дескриптор fd из списка интереса для экземпляра epfd. Аргумент ev при этом игнорируется. При попытке удалить файловый дескриптор, не входящий в список интереса, вызов epoll_ctl() завершится ошибкой ENOENT. Закрытие файлового дескриптора автоматически удаляет его из всех списков интереса epoll, в которые он входит.
Аргумент ev является указателем на структуру типа epoll_event следующего вида:
struct epoll_event {
uint32_t events; /* События epoll (битовая маска) */
epoll_data_t data; /* Пользовательские данные */
};
Поле data структуры epoll_event выглядит так:
typedef union epoll_data {
void *ptr; /* Указатель на пользовательские данные */
int fd; /* Файловый дескриптор */
uint32_t u32; /* 32-разрядное целое число */
uint64_t u64; /* 64-разрядное целое число */
} epoll_data_t;
Аргумент ev определяет параметры для файлового дескриптора fd.
• Вложенное поле events представляет собой битовую маску, определяющую набор интересующих нас событий для дескриптора fd. Более подробно о ее битовых значениях будет рассказано в следующем разделе.
• Вложенное поле data является объединением, где один из элементов можно задействовать для описания информации, которая должна возвращаться обратно вызывающему процессу (через вызов epoll_wait()) в случае готовности дескриптора fd.
Пример использования вызовов epoll_create() и epoll_ctl() продемонстрирован в листинге 59.4.
Листинг 59.4. Применение вызовов epoll_create() и epoll_ctl()
int epfd;
struct epoll_event ev;
epfd = epoll_create(5);
if (epfd == -1)
errExit("epoll_create");
ev.data.fd = fd;
ev.events = EPOLLIN;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)
errExit("epoll_ctl");
Для каждого файлового дескриптора, регистрируемого в списке интереса epoll, выделяется небольшой объем памяти ядра, которую нельзя сбрасывать на диск. Поэтому ядро предоставляет интерфейс, определяющий максимальное количество дескрипторов, доступных для регистрации каждому пользователю. Значение данного ограничения можно просматривать и изменять с помощью файла max_user_watches в каталоге /proc/sys/fs/epoll (доступен только в Linux). По умолчанию данное ограничение вычисляется на основе доступной в системе памяти (см. страницу epoll(7) руководства).
59.4.3. Ожидание событий: вызов epoll_wait()
Системный вызов epoll_wait() возвращает информацию о готовых файловых дескрипторах из экземпляра epoll, на который указывает дескриптор epfd. За одно выполнение этот вызов может вернуть сведения о множестве готовых дескрипторов.
#include
int epoll_wait(int
int
Возвращает количество готовых файловых дескрипторов, 0, если истекло время ожидания, или -1 при ошибке