Главная » 2017 » Ноябрь » 17 » man 2 eventfd2
01:36
man 2 eventfd2

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


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



ОБЗОР


#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:

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

* Если флаг EFD_SEMAPHORE задан указан и счётчик eventfd не равен нулю, то
read(2) возвращает 8 байт, содержащие значение 1, и значение счётчика
уменьшается на 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" без блокировки.

* Если обнаружено переполнение счётчика, то select(2) указывает на
файловый дескриптор, доступный на чтение и запись, и poll(2) возвращает
событие POLLERR. Как упоминалось ранее, write(2) никогда не может
вызвать переполнение счётчика. Однако переполнение может произойти, если
подсистемой KAIO выполнится (возможно теоретически) 2^64 "передач
сигналов" eventfd. Если переполнение произошло, то read(2) вернёт
максимальное значение типа uint64_t (т.е., 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() │ Безвредность в нитях │ 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.

Пример сеанса работы с программой:


Исходный код программы

#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");
}

Категория: (2) Системные вызовы ядра (функции языка Си) | Просмотров: 581 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar