.\" -*- coding: UTF-8 -*- .\" Copyright 2003, Davide Libenzi .\" Copyright, the authors of the Linux man-pages project .\" .\" SPDX-License-Identifier: GPL-2.0-or-later .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH epoll 7 "8 февраля 2026 г." "Linux man\-pages 6.18" .SH НАИМЕНОВАНИЕ epoll \- средство уведомления о событии ввода\-вывода .SH СИНТАКСИС .nf \fB#include \fP .fi .SH ОПИСАНИЕ Программный интерфейс \fBepoll\fP выполняется схожую с \fBpoll\fP(2) задачу: следит за несколькими файловыми дескрипторами и ждёт, когда станет возможен ввод\-вывод для одного из них. Программный интерфейс \fBepoll\fP можно использовать либо в режиме edge\-triggered, либо в level\-triggered и применять для слежения за достаточно большим количеством файловых дескрипторов. .P Центральным элементом программного интерфейса \fBepoll\fP является \fIэкземпляр\fP \fBepoll\fP — структура данных ядра, которая с точки зрения пользовательского пространства может рассматриваться как контейнер с двумя списками: .IP \[bu] 3 Список \fIinterest\fP (иногда также называемый набором \fBepoll\fP): набор файловых дескрипторов, которые зарегистрировал процесс для слежения. .IP \[bu] The \fIready\fP list: the set of file descriptors that are "ready" for I/O. The ready list is a subset of (or, more precisely, a set of references to) the file descriptors in the interest list. The ready list is dynamically populated by the kernel as a result of I/O activity on those file descriptors. .P Для создания и управления экземпляром \fBepoll\fP служат следующие системные вызовы: .IP \[bu] 3 Вызов \fBepoll_create\fP(2) создаёт экземпляр новый \fBepoll\fP и возвращает файловый дескриптор, указывающий на этот экземпляр (более новый \fBepoll_create1\fP(2) расширяет возможности \fBepoll_create\fP(2)). .IP \[bu] Затем с помощью \fBepoll_ctl\fP(2) регистрируются интересующие файловые дескрипторы, который добавляет их в список interest экземпляра \fIepoll\fP. .IP \[bu] .\" Вызов \fBepoll_wait\fP(2) ждёт наступления событий ввода\-вывода, блокируя вызывающую нить, если события пока недоступны (данный системный вызов можно рассматривать как выборщике элементов из списка готовности экземпляра \fBepoll\fP). .SS "Режимы level\-triggered и edge\-triggered" Существует два режима выдачи событий \fBepoll\fP: edge\-triggered (ET) и level\-triggered (LT). Разницу между ними можно описать так. Предположим, что реализован следующий сценарий событий: .IP (1) 5 Файловый дескриптор, представляющий читающую сторону канала (\fIrfd\fP), регистрируется в экземпляре \fBepoll\fP. .IP (2) Пишущая сторона канала записывает 2\ КБ данных на записываемой стороне канала. .IP (3) Вызов \fBepoll_wait\fP(2) завершается и возвращает \fIrfd\fP как готовый файловый дескриптор. .IP (4) Читающая сторона канала считывает 1\ КБ данных из \fIrfd\fP. .IP (5) Вызов \fBepoll_wait\fP(2) завершается. .P If the \fIrfd\fP file descriptor has been added to the \fBepoll\fP interface using the \fBEPOLLET\fP (edge\-triggered) flag, the call to \fBepoll_wait\fP(2) done in step \fB5\fP will probably hang despite the available data still present in the file input buffer; meanwhile the remote peer might be expecting a response based on the data it already sent. The reason for this is that edge\-triggered mode delivers events only when changes occur on the monitored file descriptor, that is, an event will be generated upon each receipt of a chunk of data. So, in step \fB5\fP the caller might end up waiting for some data that is already present inside the input buffer. In the above example, an event on \fIrfd\fP will be generated because of the write done in \fB2\fP and the event is consumed in \fB3\fP. Since the read operation done in \fB4\fP does not consume the whole buffer data, the call to \fBepoll_wait\fP(2) done in step \fB5\fP might block indefinitely. .P Приложение, которое применяет флаг \fBEPOLLET\fP, должно использовать неблокирующие файловые дескрипторы, чтобы избежать приостановки задания, обрабатывающего множество файловых дескрипторов, из\-за блокировок чтения или записи. Предлагаемый способ использования \fBepoll\fP с интерфейсом Edge Triggered (\fBEPOLLET\fP): .IP (1) 5 неблокирующие файловые дескрипторы; и .IP (2) ожидание события только после того, как \fBread\fP(2) или \fBwrite\fP(2) возвратят \fBEAGAIN\fP. .P Напротив, при использовании интерфейса level\-triggered (по умолчанию, если не указан \fBEPOLLET\fP) \fBepoll\fP проще и быстрее \fBpoll\fP(2), и может быть использован везде, где используется последний, так как имеет ту же семантику. .P Так как даже с edge\-triggered \fBepoll\fP при получении нескольких порций данных могут генерироваться множественные события, вызывающий может задать флаг \fBEPOLLONESHOT\fP, который указывает \fBepoll\fP отключить связанный файловый дескриптор после приёма события с помощью \fBepoll_wait\fP(2). Если указан флаг \fBEPOLLONESHOT\fP, то вызывающий должен переустановить файловый дескриптор с помощью \fBepoll_ctl\fP(2) с флагом \fBEPOLL_CTL_MOD\fP. .P .\" If multiple threads (or processes, if child processes have inherited the \fBepoll\fP file descriptor across \fBfork\fP(2)) are blocked in \fBepoll_wait\fP(2) waiting on the same epoll file descriptor and a file descriptor in the interest list that is marked for edge\-triggered (\fBEPOLLET\fP) notification becomes ready, just one of the threads (or processes) is awoken from \fBepoll_wait\fP(2). This provides a useful optimization for avoiding "thundering herd" wake\-ups in some scenarios. .SS "Взаимодействие с autosleep" Если система в режиме \fBautosleep\fP посредством \fI/sys/power/autosleep\fP и происходит событие, которое пробуждает устройство, то драйвер устройства держит устройство проснувшимся только, пока событие ставится в очередь. Чтобы устройство не заснуло пока не обработает событие, необходимо использовать флаг \fBepoll_ctl\fP(2) \fBEPOLLWAKEUP\fP. .P Флаг \fBEPOLLWAKEUP\fP задаётся в поле \fBevents\fP для \fIstruct epoll_event\fP; система будет оставаться разбуженной с момента когда событие поступает в очередь, пока не закончится работа вызова \fBepoll_wait\fP(2), возвращающий событие, и до последующего вызова \fBepoll_wait\fP(2). Если событие должно держать систему разбуженной дольше, то нужно применить отдельный \fIwake_lock\fP перед вторым вызовом \fBepoll_wait\fP(2). .SS "Интерфейс /proc" .\" Following was added in Linux 2.6.28, but them removed in Linux 2.6.29 .\" .TP .\" .IR /proc/sys/fs/epoll/max_user_instances " (since Linux 2.6.28)" .\" This specifies an upper limit on the number of epoll instances .\" that can be created per real user ID. Для ограничения потребления epoll памяти ядра, можно использовать следующие интерфейсы: .TP \fI/proc/sys/fs/epoll/max_user_watches\fP (начиная с Linux 2.6.28) .\" Linux 2.6.29 (in Linux 2.6.28, the default was 1/32 of lowmem) Задаёт ограничение на общее количество файловых дескрипторов, которые пользователь может зарегистрировать во всех экземплярах epoll в системе. Ограничение привязывается к реальному идентификатору пользователя. Каждый зарезервированный файловый дескриптор занимает, приблизительно, 90 байт в 32\-битном ядре, и, приблизительно, 160 байт в 64\-битном ядре. В настоящее время, значение по умолчанию для \fImax_user_watches\fP равно 1/25 (4%) доступной памяти ядра (low memory), поделённое на значение размера дескриптора в байтах. .SS "Примеры использования" При применении \fBepoll\fP с интерфейсом level\-triggered он имеет ту же семантику что и \fBpoll\fP(2), а при edge\-triggered требует больших проверок для избежания зависаний приложения в событийном цикле. В этом примере, слушающим является неблокирующий сокет, для которого был вызван \fBlisten\fP(2). Функция \fIdo_use_fd\fP() использует новый готовый файловый дескриптор до тех пор, пока не возвратится \fBEAGAIN\fP от \fBread\fP(2) или \fBwrite\fP(2). Приложение на основе машины состояний должно после получения \fBEAGAIN\fP записать своё текущее состояние так, чтобы последующий вызов \fIdo_use_fd\fP() продолжил выполнять \fBread\fP(2) или \fBwrite\fP(2) с места остановки. .P .in +4n .EX #define MAX_EVENTS 10 struct epoll_event ev, events[MAX_EVENTS]; int listen_sock, conn_sock, nfds, epollfd; \& /* Code to set up listening socket, \[aq]listen_sock\[aq], (socket(), bind(), listen()) omitted. */ \& epollfd = epoll_create1(0); if (epollfd == \-1) { perror("epoll_create1"); exit(EXIT_FAILURE); } \& ev.events = EPOLLIN; ev.data.fd = listen_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == \-1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } \& for (;;) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, \-1); if (nfds == \-1) { perror("epoll_wait"); exit(EXIT_FAILURE); } \& for (n = 0; n < nfds; ++n) { if (events[n].data.fd == listen_sock) { conn_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen); if (conn_sock == \-1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == \-1) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { do_use_fd(events[n].data.fd); } } } .EE .in .P При использовании интерфейса edge\-triggered для большей производительности можно однократно добавить файловый дескриптор внутрь интерфейса \fBepoll\fP (\fBEPOLL_CTL_ADD\fP), указав (\fBEPOLLIN\fP|\fBEPOLLOUT\fP). Это позволит вам избежать постоянного переключения между \fBEPOLLIN\fP и \fBEPOLLOUT\fP, вызывающими \fBepoll_ctl\fP(2) c \fBEPOLL_CTL_MOD\fP. .SS "Вопросы и ответы" .IP \[bu] 3 По какому ключу различать зарегистрированные файловые дескрипторы в списке interest? .IP Уникальной комбинацией является номер файлового дескриптора и описание открытого файла (так называемый «описатель открытого файла» — внутреннее представление открытого файла в ядре). .IP \[bu] Что случится, если зарегистрировать один файловый дескриптор в экземпляре \fBepoll\fP дважды? .IP .\" But a file descriptor duplicated by fork(2) can't be added to the .\" set, because the [file *, fd] pair is already in the epoll set. .\" That is a somewhat ugly inconsistency. On the one hand, a child process .\" cannot add the duplicate file descriptor to the epoll set. (In every .\" other case that I can think of, file descriptors duplicated by fork have .\" similar semantics to file descriptors duplicated by dup() and friends.) On .\" the other hand, the very fact that the child has a duplicate of the .\" file descriptor means that even if the parent closes its file descriptor, .\" then epoll_wait() in the parent will continue to receive notifications for .\" that file descriptor because of the duplicated file descriptor in the child. .\" .\" See http://thread.gmane.org/gmane.linux.kernel/596462/ .\" "epoll design problems with common fork/exec patterns" .\" .\" mtk, Feb 2008 Вероятно, вы получите \fBEEXIST\fP. Однако возможно добавить дубликат файлового дескриптора (\fBdup\fP(2), \fBdup2\fP(2), \fBfcntl\fP(2) \fBF_DUPFD\fP) в тот же экземпляр \fBepoll\fP. Это может быть полезно для фильтрующих событий, если дубликаты файловых дескрипторов регистрируются с разными масками \fIevents\fP. .IP \[bu] Могут ли два экземпляра \fBepoll\fP ожидать один файловый дескриптор? Если да, то сообщаются ли события в оба файловых дескриптора \fBepoll\fP? .IP Да, и события будут доходить в оба. Однако, чтобы сделать это правильно, нужна внимательность к деталям. .IP \[bu] Могут ли операции poll/epoll/select применяться к самому файловому дескриптору \fBepoll\fP? .IP Да. Если файловый дескриптор \fBepoll\fP имеет ожидающие события, то он будет помечен как доступный для чтения. .IP \[bu] Что случится, если попытаться поместить файловый дескриптор \fBepoll\fP в свой собственный набор файловых дескрипторов? .IP Вызов \fBepoll_ctl\fP(2) завершается ошибкой (\fBEINVAL\fP). Однако вы можете добавить файловый дескриптор \fBepoll\fP внутрь другого набора файлового дескриптора \fBepoll\fP. .IP \[bu] Можно ли отправить файловый дескриптор \fBepoll\fP через доменный сокет UNIX другому процессу? .IP Да, но это не имеет смысла, так как принимающий процесс не имеет копий файловых дескрипторов в списке interest. .IP \[bu] Приводит ли закрытие файлового дескриптора к его удалению из всех списков interest \fBepoll\fP? .IP Да, но учтите следующий момент. Файловый дескриптор является ссылкой на открытое файловое описание (смотрите \fBopen\fP(2)). При создании дубля файлового дескриптора с помощью \fBdup\fP(2), \fBdup2\fP(2), \fBfcntl\fP(2) \fBF_DUPFD\fP или \fBfork\fP(2) созданный новый файловый дескриптор указывает на то же открытое файловое описание. Открытое файловое описание продолжает существовать до тех пор, пока все указывающие на него файловые дескрипторы не будут закрыты. .IP Файловый дескриптор удаляется из списка interest только после того, как будут закрыты все файловые дескрипторы, ссылающиеся на открытое файловое описание. Это означает, что даже после закрытия файлового дескриптора, являющегося частью списка interest, могут поступать события от файлового дескриптора, если остались открытыми другие файловые дескрипторы, ссылающиеся на тоже файловое описание. Чтобы такого не случалось, файловый дескриптор должен быть удалён из списка interest явным образом (с помощью \fBepoll_ctl\fP(2) \fBEPOLL_CTL_DEL\fP) до создания его дубликата. Или же приложение может проверить,что закрыты все файловые дескрипторы (что может быть трудно, если дубли файлового дескриптора неявно создавались где\-то в библиотечных функциях с помощью \fBdup\fP(2) или \fBfork\fP(2)). .IP \[bu] Если между вызовами \fBepoll_wait\fP(2) придёт более одного события, то они будут объединены или о них будет сообщено по отдельности? .IP Они будут объединены. .IP \[bu] Влияет ли операция над файловым дескриптором на уже собранные, но пока ещё не сообщенные события? .IP Вы можете выполнить две операции на существующем файловом дескрипторе. Удаление в этом случае бессмысленно. Изменение приведёт к повторному чтению доступного ввода/вывода. .IP \[bu] Должен ли я читать/записывать файловый дескриптор до пор пока, не получу \fBEAGAIN\fP при использовании флага \fBEPOLLET\fP (поведение edge\-triggered)? .IP Получение события от \fBepoll_wait\fP(2) должно сообщить вам, что файловый дескриптор готов для запрошенной операции ввода/вывода. Вы должны предполагать, что он готов до тех пор, пока вы не получите следующий \fBEAGAIN\fP от (неблокирующего) чтения/записи. Когда и как вы будете использовать файловый дескриптор — полностью зависит от вас. .IP Для пакетных/метко ориентированных файлов (например, датаграмных сокетов, терминал в каноническом режиме) единственным способом обнаружить конец чтения/записи пространства ввода\-вывода — это продолжать чтение/записи до получения \fBEAGAIN\fP. .IP Для потокоориентированных файлов (например, каналы, FIFO, потоковые сокеты) условие, при которых чтение/запись пространства ввода/вывода закончилось, может быть определено проверкой количества считанных/записанных данных из/в целевого файлового дескриптора. Например, если вы вызвали \fBread\fP(2) для чтения определённого количества данных и \fBread\fP(2) вернул меньшее количество байтов, то можно быть уверенным, что пространство чтения ввода/вывода этого файлового дескриптора закончилось. То же самое справедливо для записи посредством \fBwrite\fP(2) (не используйте последнее, если вы не можете гарантировать, что отслеживаемый файловый дескриптор всегда ссылается на потокоориентированный файл). .SS "Возможные ловушки и способы их обхода" .IP \[bu] 3 \fBStarvation (edge\-triggered)\fP .IP Если существует большое пространство ввода/вывода, то возможно, что пока вы его читаете, другие файлы не будут обрабатываться и возникнет недостаток данных (этого, обычно, не происходит с \fBepoll\fP). .IP Решением будет поддержка списка готовности и маркировка файлового дескриптора как готового в связанной с ним структуре данных, тем самым позволяя приложению запоминать какие файлы требуют обработки, но всё ещё не обработанных среди уже готовых файлов. Это также поддерживает игнорирование последующих событий готовности файловых дескрипторов, получаемых вами. .IP \[bu] \fBIf using an event cache...\fP .IP Если вы используете кэш событий или храните все файловые дескрипторы, возвращённые от \fBepoll_wait\fP(2), то убедитесь, что вы обеспечили способ его динамического закрытия (например, вызванное обработкой предыдущего события). Предположим, что вы получили 100 событий от \fBepoll_wait\fP(2), и что в событии №47 некоторое условие определяет, что событие №13 должно быть закрыто. Если вы удалите структуру и выполните \fBclose\fP(2) файлового дескриптора для события №13, то кэш событий всё ещё может сообщать о том, что есть ожидаемые события для этого файлового дескриптора, что приводит к путнице. .IP Одним из решений будет вызов, во время обработки события №47, \fBepoll_ctl\fP(\fBEPOLL_CTL_DEL\fP) для удаления файлового дескриптора 13 и вызов \fBclose\fP(2), а затем маркировка связанной с ним структуры данных как удалённой и связки его со списком очистки. Если при пакетной обработке найдется другое событие для файлового дескриптора 13, то обнаружится, что файловый дескриптор уже был удалён и конфликтов не будет. .SH ВЕРСИИ Some other systems provide similar mechanisms; for example, FreeBSD has \fIkqueue\fP, and Solaris has \fI/dev/poll\fP. .SH СТАНДАРТЫ Linux. .SH ИСТОРИЯ .\" Its interface should be finalized in Linux 2.5.66. Linux 2.5.44. glibc 2.3.2. .SH ПРИМЕЧАНИЯ The set of file descriptors that is being monitored via an epoll file descriptor can be viewed via the entry for the epoll file descriptor in the process's \fI/proc/\fPpid\fI/fdinfo\fP directory. See \fBproc\fP(5) for further details. .P Вызов The \fBkcmp\fP(2) с операцией \fBKCMP_EPOLL_TFD\fP можно использовать для проверки, что файловый дескриптор присутствует в экземпляре epoll. .SH "СМОТРИТЕ ТАКЖЕ" \fBepoll_create\fP(2), \fBepoll_create1\fP(2), \fBepoll_ctl\fP(2), \fBepoll_wait\fP(2), \fBioctl_eventpoll\fP(2), \fBpoll\fP(2), \fBselect\fP(2) .PP .SH ПЕРЕВОД Русский перевод этой страницы руководства разработал(и) Azamat Hackimov , Yuri Kozlov и Иван Павлов . .PP Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, .UR https://www.gnu.org/licenses/gpl-3.0.html .UE версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. .PP Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу .MT debian-l10n-russian@lists.debian.org списка рассылки русских переводчиков .ME .