ОБЗОР
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
ОПИСАНИЕ
Вызов eventfd() создаёт «объект eventfd», который можно использовать в
качестве механизма ожидания/уведомления о событиях в приложениях
пространства пользователя и ядра. Объект содержит беззнаковое 64-битный
(uint64_t) счётчик, обслуживаемый ядром. Этот счётчик инициализируется
значением, указанным в аргументе initval.
Для изменения поведения eventfd() можно использовать следующие значения flags (через OR):
EFD_CLOEXEC (начиная с Linux 2.6.27) Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового открытого файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для того, чтобы узнать как это может пригодиться.
EFD_NONBLOCK (начиная с Linux 2.6.27) Устанавливает флаг состояния файла O_NONBLOCK для нового открытого файлового дескриптора. Использование данного флага заменяет дополнительные вызовы fcntl(2) для достижения того же результата.
EFD_SEMAPHORE (начиная с Linux 2.6.30) Предоставляет семафоро-подобную семантику для чтения из нового файлового дескриптора. Смотрите ниже.
До версии Linux 2.6.26 аргумент flags не использовался, и должен быть равен нулю.
При завершении работы eventfd() возвращает новый файловый дескриптор, который можно использовать для ссылки на объект eventfd. Над этим файловым дескриптором можно выполнять следующие операции:
read(2) Каждый выполнившийся вызов read(2) возвращает 8-байтное целое. Вызов read(2) завершится с ошибкой EINVAL, если размер указанного буфера будет меньше 8 байт.
Возвращаемое read(2) значение имеет порядок байт узла, т. е., используемый порядок байт для целых на машине узла. Семантика read(2) зависит от значения счётчика eventfd — равно оно нулю или нет, и был ли указан флаг EFD_SEMAPHORE при создании файлового дескриптора eventfd:write(2) При вызове write(2) из его буфера к счётчику добавляется 8-байтовое целое значение. Максимальное значение, которое может храниться в счётчике, равно наибольшему 64-битному беззнаковому значению минус 1 (т.е., 0xfffffffffffffffe). Если при добавлении значение счётчика превысит максимум, то write(2) заблокируется до тех пор, пока для файлового дескриптора не будет выполнен вызов read(2), или завершится с ошибкой EAGAIN, если файловый дескриптор создан неблокируемым.
Вызов write(2) завершится с ошибкой EINVAL, если размер указанного буфера меньше 8 байт, или если попытаться записать значение 0xffffffffffffffff.poll(2), select(2) (и подобные) Возвращённый файловый дескриптор поддерживает poll(2) (и, аналогично, epoll(7)) и select(2) следующим образом:
close(2) Если файловый дескриптор больше не требуется, его нужно закрыть. Когда все файловые дескрипторы, связанные с одним объектом eventfd, будут закрыты, ядро освобождает ресурсы объекта.
Копия файлового дескриптора, созданного eventfd(), наследуется потомком, созданным с помощью fork(2). Копия файлового дескриптора связывается с тем же объектом eventfd. Файловые дескрипторы, созданные eventfd(), сохраняются при вызове execve(2), если не указан флаг закрытия-при-exec.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении eventfd() возвращает новый файловый дескриптор
eventfd. При ошибке возвращается -1, и errno устанавливается в
соответствующее значение.
ОШИБКИ
EINVAL В flags указано неподдерживаемое значение.
EMFILE Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.
ENFILE Достигнуто максимальное количество открытых файлов в системе.
ENODEV Не удалось смонтировать (внутреннее) безымянное устройство inode.
ENOMEM Недостаточно памяти для создания нового файлового дескриптора eventfd.
ВЕРСИИ
Вызов eventfd() доступен в Linux начиная с ядра 2.6.22. Поддержка в glibc появилась в версии 2.8. Системный вызов eventfd2() (см.ЗАМЕЧАНИЯ) доступен в Linux начиная с ядра 2.6.27. В glibc версии 2.9 в обёртке eventfd() используется системный вызов eventfd2(), если он поддерживается ядром.
АТРИБУТЫ
Описание терминов данного раздела смотрите в 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).)
Отличия между библиотекой C и ядром
Основу составляют два системных вызова Linux: eventfd() и более новый eventfd2(). В первом системном вызове не реализован аргумент flags. Последний системный вызов использует значения flags, которые были описаны ранее. Обёрточная функция glibc использует eventfd2(), если он доступен.Дополнительные возможности glibc
В библиотеке 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 <sys/eventfd.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> /* определение uint64_t */ #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { int efd, j; 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) handle_error("eventfd"); switch (fork()) { case 0: for (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)) handle_error("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)) handle_error("read"); printf("Parent read %llu (0x%llx) from efd\n", (unsigned long long) u, (unsigned long long) u); exit(EXIT_SUCCESS); case -1: handle_error("fork"); } }