Epoll (Epoll)
Epoll (event poll) — API мультиплексированного ввода-вывода, предоставляемого Linux для приложений. API позволяет приложениям осуществлять мониторинг нескольких открытых файловых дескрипторов (которые могут быть файлами, устройствами или сокетами, в том числе сетевыми), для того, чтобы узнать, готово ли устройство для продолжения ввода (вывода). Epoll планировался как более эффективная замена вызовам select()
и poll()
, определёнными в POSIX. Epoll может предоставить более эффективный механизм для приложений, обрабатывающих большое количество одновременно открытых соединений — со сложностью O(1) в отличие от стандартного механизма, обладающего сложностью O(n). Epoll аналогичен системе Kqueue из FreeBSD и также представляет собой объект ядра, предоставляемый для работы в пространстве пользователя в виде файлового дескриптора.
По аналогии "epoll" часто называют другие подобные решения, схожие по методике.
Проблема select/poll
[править | править код]Для использования select или poll приложение должно передать в ядро полный список всех файловых дескрипторов, в которых оно ожидает появление данных; а ядро, в свою очередь, должно для каждого из переданных элементов проверить состояние дескрипторов и сформировать структуру, описывающую состояние каждого переданного дескриптора. Такой подход не создаст много проблем в условиях десятков или сотен дескрипторов. Тем не менее, производительность в больших сетях заметно падает.
Описание epoll API
[править | править код]Linux предоставляет следующие вызовы в рамках API:
- epoll_create() — создаёт структуру данных (epoll instance), с которой в дальнейшем идёт работа. Структура одна для всех файловых дескрипторов, за которыми идёт наблюдение. Функция возвращает файловый дескриптор, который в дальнейшем передаётся во все остальные вызовы epoll API.
- epoll_ctl() — используется для управления epoll instance, в частности, позволяет выполнять операции EPOLL_CTL_ADD (добавление файлового дескриптора к наблюдению), EPOLL_CTL_DEL (удаление файлового дескриптора из наблюдения), EPOLL_CTL_MOD (изменение параметров наблюдения), EPOLL_CTL_DISABLE (добавлена в Linux 3.7) — для безопасного отключения наблюдения за файловым дескриптором в многопоточных приложениях
- epoll_wait() — возвращает количество (один или более) файловых дескрипторов из списка наблюдения, у которых поменялось состояние (которые готовы к вводу-выводу).
- Прототипы функций
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
Принцип работы: после того, как приложение добавляет дескрипторы к наблюдению и вызывает epoll_wait(), при готовности какого-либо дескриптора (появлению информации, опустошению буфера и т. д.) ядро возвращает приложение из epoll_wait со списком файловых дескрипторов, которые готовы к работе. Если какие-то дескрипторы становятся готовыми к работе до вызова epoll_wait, то они отмечаются соответствующим образом и при следующем вызове epoll_wait управление в приложение возвращается сразу же со списком готовых к работе файловых дескрипторов.
События, за которыми можно наблюдать с помощью epoll:
- EPOLLIN — новые данные (для чтения) в файловом дескрипторе
- EPOLLOUT — файловый дескриптор готов продолжить принимать данные (для записи)
- EPOLLERR — в файловом дескрипторе произошла ошибка
- EPOLLHUP — закрытие файлового дескриптора
Режимы работы
[править | править код]epoll позволяет работать в двух режимах:
- edge-triggered — файловый дескриптор с событием возвращается, только если с момента последнего возврата произошли новые события (например, пришли новые данные)
- level-triggered — файловый дескриптор возвращается, если остались непрочитанные/записанные данные
Если приложение прочитало из файлового дескриптора только часть доступных для чтения данных, то при следующем вызове:
- в edge-triggered файловый дескриптор не будет возвращён до тех пор, пока в дескрипторе не появятся новые данные;
- в level-triggered файловый дескриптор будет возвращаться до тех пор, пока не прочитаны все «старые» данные (и новые, если таковые придут)
Управление
[править | править код]Начиная с 2.6.28 /proc/sys/fs/epoll/max_user_watches указывает максимальное число файловых дескрипторов, за которыми может наблюдать пользователь.