| eventfd(2) | System Calls Manual | eventfd(2) |
eventfd - создаёт файловый дескриптор для уведомления о событиях
Стандартная библиотека языка C (libc, -lc)
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
Вызов eventfd() создаёт «объект eventfd», который можно использовать в качестве механизма ожидания/уведомления о событиях в приложениях пространства пользователя и ядра. Объект содержит беззнаковое 64-битный (uint64_t) счётчик, обслуживаемый ядром. Этот счётчик инициализируется значением, указанным в аргументе initval.
При завершении работы eventfd() возвращает новый файловый дескриптор, который можно использовать для ссылки на объект eventfd.
Для изменения поведения eventfd() можно использовать следующие значения flags (через OR):
До Linux 2.6.26 аргумент flags не используется и должен быть указан как ноль.
Следующие операции могут выполняться над полученным файловым дескриптором eventfd():
Копия файлового дескриптора, созданного eventfd(), наследуется потомком, созданным с помощью fork(2). Копия файлового дескриптора связывается с тем же объектом eventfd. Файловые дескрипторы, созданные eventfd(), сохраняются при вызове execve(2), если не указан флаг close-on-exec.
При успешном выполнении eventfd() возвращает новый файловый дескриптор eventfd. При ошибке возвращается -1, и errno устанавливается в соответствующее значение.
Описание терминов данного раздела смотрите в attributes(7).
| Интерфейс | Атрибут | Значение |
| eventfd() | Безвредность в нитях | MT-Safe |
Основу составляют два системных вызова Linux: eventfd() и более новый eventfd2(). В первом системном вызове не реализован аргумент flags. Последний системный вызов использует значения flags, которые были описаны ранее. Обёрточная функция glibc использует eventfd2(), если он доступен.
В библиотеке GNU C определён дополнительный тип и две функции, которые пытаются устранить сложности чтения и записи из файлового дескриптора eventfd:
typedef uint64_t eventfd_t; int eventfd_read(int fd, eventfd_t *value); int eventfd_write(int fd, eventfd_t value);
Функции выполняют операции чтения и записи из файлового дескриптора eventfd, и возвращают 0, если передано правильное количество байт и -1 в противном случае.
Linux, GNU.
Приложения могут использовать файловый дескриптор eventfd вместо канала (см. pipe(2)) во всех случаях, когда канал используется только для сигнализации о событиях. Издержки ядра по файловому дескриптору eventfd намного меньше, чем по каналу и требуется только один файловый дескриптор (против двух, при использовании канала).
При использовании в ядре файловый дескриптор eventfd может предоставлять мост из ядерного в пользовательское пространство, позволяя например работать, подобно KAIO ( ядерный AIO), сигнализируя, что завершена какая-то операция над файловым дескриптором.
Важным моментом файлового дескриптора eventfd является то, что за ним можно следить как за обычным файловым дескриптором с помощью select(2), poll(2) или epoll(7). Это означает, что приложение может одновременно отслеживать готовность "обычных" файлов и готовность других механизмов ядра, которые поддерживают интерфейс eventfd. (Без интерфейса eventfd() эти механизмы невозможно мультиплексировать через select(2), poll(2) или epoll(7).)
Текущее значение счётчика eventfd можно найти в записи для соответствующего файлового дескриптора в каталоге процесса /proc/pid/fdinfo. Подробности смотрите в proc(5).
Следующая программа создаёт файловый дескриптор eventfd и затем создаёт дочерний процесс. Пока родительский процесс на короткое время засыпает, потомок пишет все числа, переданные в командной строке программы, в файловый дескриптор eventfd. Когда родитель просыпается, он читает их из файлового дескриптора eventfd.
Пример сеанса работы с программой:
$ ./a.out 1 2 4 7 14 Child writing 1 to efd Child writing 2 to efd Child writing 4 to efd Child writing 7 to efd Child writing 14 to efd Child completed write loop Parent about to read Parent read 28 (0x1c) from efd
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int efd;
uint64_t u;
ssize_t s;
if (argc < 2) {
fprintf(stderr, "Usage: %s <num>...\n", argv[0]);
exit(EXIT_FAILURE);
}
efd = eventfd(0, 0);
if (efd == -1)
err(EXIT_FAILURE, "eventfd");
switch (fork()) {
case 0:
for (size_t j = 1; j < argc; j++) {
printf("Child writing %s to efd\n", argv[j]);
u = strtoull(argv[j], NULL, 0);
/* strtoull() allows various bases */
s = write(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
err(EXIT_FAILURE, "write");
}
printf("Child completed write loop\n");
exit(EXIT_SUCCESS);
default:
sleep(2);
printf("Parent about to read\n");
s = read(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
err(EXIT_FAILURE, "read");
printf("Parent read %"PRIu64" (%#"PRIx64") from efd\n", u, u);
exit(EXIT_SUCCESS);
case -1:
err(EXIT_FAILURE, "fork");
}
}
futex(2), pipe(2), poll(2), read(2), select(2), signalfd(2), timerfd_create(2), write(2), epoll(7), sem_overview(7)
Русский перевод этой страницы руководства разработал(и) Azamat Hackimov <azamat.hackimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
| 15 июня 2024 г. | Справочные страницы Linux 6.9.1 |