eventfd(2) | System Calls Manual | eventfd(2) |
eventfd - создаёт файловый дескриптор для уведомления о событиях
Standard C library (libc, -lc)
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
Вызов eventfd() создаёт «объект eventfd», который можно использовать в качестве механизма ожидания/уведомления о событиях в приложениях пространства пользователя и ядра. Объект содержит беззнаковое 64-битный (uint64_t) счётчик, обслуживаемый ядром. Этот счётчик инициализируется значением, указанным в аргументе initval.
При завершении работы eventfd() возвращает новый файловый дескриптор, который можно использовать для ссылки на объект eventfd.
Для изменения поведения eventfd() можно использовать следующие значения flags (через OR):
Up to Linux 2.6.26, the flags argument is unused, and must be specified as zero.
Следующие операции могут выполняться над полученным файловым дескриптором eventfd():
Копия файлового дескриптора, созданного eventfd(), наследуется потомком, созданным с помощью fork(2). Копия файлового дескриптора связывается с тем же объектом eventfd. Файловые дескрипторы, созданные eventfd(), сохраняются при вызове execve(2), если не указан флаг close-on-exec.
При успешном выполнении eventfd() возвращает новый файловый дескриптор eventfd. При ошибке возвращается -1, и errno устанавливается в соответствующее значение.
eventfd() is available since Linux 2.6.22. Working support is provided since glibc 2.8. The eventfd2() system call (see NOTES) is available since Linux 2.6.27. Since glibc 2.9, the eventfd() wrapper will employ the eventfd2() system call, if it is supported by the kernel.
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение |
eventfd() | Безвредность в нитях | MT-Safe |
Вызовы eventfd() и eventfd2() есть только в Linux.
Приложения могут использовать файловый дескриптор 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).
Основу составляют два системных вызова 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 в противном случае.
Следующая программа создаёт файловый дескриптор 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 <unistd.h> int main(int argc, char *argv[]) { int efd; uint64_t u; ssize_t s; if (argc < 2) { fprintf(stderr, "Использование: %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() разрешены различные основания */ 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>
Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.
Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.
10 февраля 2023 г. | Linux man-pages 6.03 |