eventfd(2)

ИМЯ
eventfd - создаёт файловый дескриптор для уведомления о событиях

LIBRARY
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):

EFD_CLOEXEC (начиная с Linux 2.6.27)
    Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового открытого файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для того, чтобы узнать как это может пригодиться.

EFD_NONBLOCK (начиная с Linux 2.6.27)
    Устанавливает флаг состояния файла O_NONBLOCK для нового открытого файлового описания (смотрите open(2)), на которое ссылается новый файловый дескриптор. Использование данного флага делает ненужными дополнительные вызовы fcntl(2) для достижения того же результата.

EFD_SEMAPHORE (начиная с Linux 2.6.30)
    Предоставляет семафоро-подобную семантику для чтения из нового файлового дескриптора. Смотрите ниже.

Up to Linux 2.6.26, the flags argument is unused, and must be specified as zero.

Следующие операции могут выполняться над полученным файловым дескриптором eventfd():

read(2)
    Каждый завершившийся без ошибок вызов read(2) возвращает 8-байтное целое. Вызов read(2) завершается с ошибкой EINVAL, если размер указанного буфера меньше 8 байт.

    The value returned by read(2) is in host byte order—that is, the native byte order for integers on the host machine.

    Семантика read(2) зависит от значения счётчика eventfd — равно оно нулю или нет, и был ли указан флаг EFD_SEMAPHORE при создании файлового дескриптора eventfd:

    •   Если флаг EFD_SEMAPHORE не указан и счётчик eventfd не равен нулю, то read(2) возвращает 8 байт с его значением и значение счётчика сбрасывается в ноль.

    •   Если флаг EFD_SEMAPHORE задан указан и счётчик eventfd не равен нулю, то read(2) возвращает 8 байт, содержащие значение 1, и значение счётчика уменьшается на 1.

    •   Если счётчик eventfd равен нулю во время вызова read(2), то вызов блокируется до тех пор, пока счётчик станет не равным нулю (время работы read(2) описано выше) или завершается с ошибкой EAGAIN, если файловый дескриптор создан неблокируемым.

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) следующим образом:

    •   Файловый дескриптор доступен для чтения (в select(2) аргумент readfds; в poll(2) флаг POLLIN), если счётчик больше 0.

    •   Файловый дескриптор доступен для записи (в select(2) аргумент writefds; в poll(2) флаг POLLOUT), если можно записать значение равное, как минимум, "1" без блокировки.

    •   If an overflow of the counter value was detected, then select(2) indicates the file descriptor as being both readable and writable, and poll(2) returns a POLLERR event. As noted above, write(2) can never overflow the counter. However an overflow can occur if 2^64 eventfd "signal posts" were performed by the KAIO subsystem (theoretically possible, but practically unlikely). If an overflow has occurred, then read(2) will return that maximum uint64_t value (i.e., 0xffffffffffffffff).

    Файловый дескриптор eventfd также поддерживает другие мультиплексные программные интерфейсы: pselect(2) и ppoll(2).

close(2)
    Если файловый дескриптор больше не требуется, его нужно закрыть. Когда все файловые дескрипторы, связанные с одним объектом eventfd, будут закрыты, ядро освобождает ресурсы объекта.

Копия файлового дескриптора, созданного eventfd(), наследуется потомком, созданным с помощью fork(2). Копия файлового дескриптора связывается с тем же объектом eventfd. Файловые дескрипторы, созданные eventfd(), сохраняются при вызове execve(2), если не указан флаг close-on-exec.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении eventfd() возвращает новый файловый дескриптор eventfd. При ошибке возвращается -1, и errno устанавливается в соответствующее значение.

ОШИБКИ

EINVAL
    В flags указано неподдерживаемое значение.

EMFILE
    Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.

ENFILE
    Достигнуто максимальное количество открытых файлов в системе.

ENODEV
    Не удалось смонтировать (внутреннее) безымянное устройство inode.

ENOMEM
    Недостаточно памяти для создания нового файлового дескриптора eventfd.

ВЕРСИИ
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).

  Отличия между библиотекой 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 <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 (https://www.gnu.org/licenses/gpl-3.0.html) или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.