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):
-
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).
Основу
составляют
два
системных
вызова 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 <
[email protected]>, Yuri Kozlov
<
[email protected]> и Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]