Scroll to navigation

POLL(2) Руководство программиста Linux POLL(2)

ИМЯ

poll, ppoll - ожидает некоторое событие над файловым дескриптором

СИНТАКСИС

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
#define _GNU_SOURCE         /* смотрите feature_test_macros(7) */
#include <signal.h>
#include <poll.h>
int ppoll(struct pollfd *fds, nfds_t nfds,
        const struct timespec *tmo_p, const sigset_t *sigmask);

ОПИСАНИЕ

poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O. The Linux-specific epoll(7) API performs a similar task, but offers features beyond those found in poll().

Отслеживаемый набор файловых дескрипторов задаётся в аргументе fds, который представляет собой массив структур:


struct pollfd {

int fd; /* файловый дескриптор */
short events; /* запрашиваемые события */
short revents; /* возвращённые события */ };

Вызывающий должен указать количество элементов в массиве fds в аргументе nfds.

В поле fd содержится файловый дескриптор открытого файла. Если значение поля отрицательно, то соответствующее поле events игнорируется, а полю revents возвращает ноль (простой способ игнорирования файлового дескриптора в одиночном вызове poll(): просто сделать значение поля fd отрицательным. Заметим, что это нельзя использовать для игнорирования файлового дескриптора 0).

Поле events представляет собой входной параметр — битовую маску, указывающую на события, происходящие с файловым дескриптором fd, которые важны для приложения. Если это поле равно нулю, то возвращаемыми событиями в revents могут быть POLLHUP, POLLERR и POLLNVAL (смотрите ниже).

Поле revents представляет собой параметр-результат, в который ядро помещает информацию о произошедших событиях. В revents могут содержаться любые битовые флаги из задаваемых в events, или там может быть одно из значений: POLLERR, POLLHUP или POLLNVAL. Эти три битовых флага не имеют смысла в поле events, но будут установлены в поле revents, если соответствующее условие истинно.

Если ни одно из запрошенных событий с файловыми дескрипторами не произошло или не возникло ошибок, то poll() блокируется до их появления.

В аргументе timeout указывается количество миллисекунд, на которые будет блокироваться poll() в ожидании готовности файлового дескриптора. Вызов будет заблокирован пока:

  • файловый дескриптор не станет готов;
  • вызов не прервётся обработчиком сигнала;
  • не истечёт время ожидания.

Заметим, что интервал timeout будет округлён с точностью системных часов, а из-за задержки при планировании в ядре блокирующий интервал будет немного больше. Отрицательное значение в timeout означает бесконечное ожидание. Значение timeout, равное нулю, приводит к немедленному завершению poll(), даже если ни один файловый дескриптор не готов.

Вот возможные биты, описанные в <poll.h>, которые могут быть установлены/получены в events и revents:

Есть данные для чтения.
Исключительное состояние файлового дескриптора. Может быть из-за:
  • Внеполосные данные в сокете TCP (смотрите tcp(7)).
  • Мастер псевдо-терминала в пакетном режиме увидел изменение состояния подчинённого терминала (смотрите ioctl_tty(2)).
  • Изменился файл cgroup.events (смотрите cgroups(7)).
Теперь запись возможна, но запись данных больше, чем доступно места в сокете или канале, по-прежнему приводит к блокировке (если не указан O_NONBLOCK).
Удалённая сторона потокового сокета закрыла соединение, или отключила запись в одну сторону. Для использования данного определения должен быть определён макрос тестирования свойств _GNU_SOURCE (до включения каких-либо заголовочных файлов).
Состояние ошибки (возвращается только в revents; игнорируется в events). Также этот бит устанавливается для файлового дескриптора, указывающего в пишущий конец канала при закрытом читающем конце.
Зависание (hang up, возвращается только в revents; игнорируется в events). Заметим, что при чтении из канала, такого как канал (pipe) или потоковый сокет, это событие всего-навсего показывает, что партнёр закрыл канал со своего конца. Дальнейшее чтение из канала будет возвращать 0 (конец файла) только после потребления всех неполученных данных в канале.
Неверный запрос: fd не открыт (возвращается только в revents; игнорируется в events).

При компилировании с установленным _XOPEN_SOURCE также определены следующие значения, которые не передают дополнительной информации вне упомянутых выше битов:

Эквивалентно POLLIN.
Доступны для чтения приоритетные внутриполосные данные (в Linux, обычно, не используется).
Эквивалентно POLLOUT.
Можно писать приоритетные данные.

В Linux также есть POLLMSG, но он не используется.

ppoll()

Отношения между poll() и ppoll() аналогичны родству select(2) и pselect(2): как pselect(2), ppoll() позволяет приложению безопасно ждать, пока файловый дескриптор не станет готов или пока не будет получен сигнал.

Кроме различия в точности аргумента timeout вызов ppoll()


ready = ppoll(&fds, nfds, tmo_p, &sigmask);

почти эквивалентен атомарному выполнению следующих вызовов:


sigset_t origmask;
int timeout;
timeout = (tmo_p == NULL) ? -1 :

(tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000); pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ready = poll(&fds, nfds, timeout); pthread_sigmask(SIG_SETMASK, &origmask, NULL);

Приведённый выше сегмент кода показывает ближайший эквивалент, так как отрицательное значение timeout в poll() рассматривается как бесконечное ожидание, а отрицательное значение в *tmo_p привело бы к ошибке ppoll().

Смотрите в pselect(2) пояснения о необходимости ppoll().

Если значение аргумента sigmask равно NULL, то изменение маски сигналов не происходит (и поэтому ppoll() отличается от poll() только в точности аргумента timeout).

В аргументе tmo_p указывается верхняя граница промежутка времени, на который будет заблокирован ppoll(). Этот аргумент представляет собой указатель на структуру следующего вида:


struct timespec {

long tv_sec; /* секунды */
long tv_nsec; /* наносекунды */ };

Если значение tmo_p равно NULL, то ppoll() может оставаться заблокированным бесконечно.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

On success, poll() returns a nonnegative value which is the number of elements in the pollfds whose revents fields have been set to a nonzero value (indicating an event or an error). A return value of zero indicates that the system call timed out before any file descriptors became read.

При ошибке возвращается -1, а в errno содержится код ошибки.

ОШИБКИ

fds points outside the process's accessible address space. The array given as argument was not contained in the calling program's address space.
Получен сигнал раньше какого-либо запрашиваемого события; смотрите signal(7).
Значение nfds превышает значение RLIMIT_NOFILE.
(ppoll()) Время ожидания в *ip некорректно (отрицательное).
Unable to allocate memory for kernel data structures.

ВЕРСИИ

Системный вызов poll() появился в Linux 2.1.23. Для старых ядер, в которых этот вызов отсутствует, glibc предоставляет обёрточную функцию poll(), которая эмулируется с помощью select(2).

Системный вызов ppoll() был добавлен в ядро Linux в версии 2.6.16. Библиотечный вызов ppoll() был добавлен в glibc 2.4.

СООТВЕТСТВИЕ СТАНДАРТАМ

Вызов poll() соответствует POSIX.1-2001 и POSIX.1-2008. Вызов ppoll() есть только в Linux.

ЗАМЕЧАНИЯ

На операции poll() и ppoll() флаг O_NONBLOCK не влияет.

В некоторых системах UNIX вызов poll() может завершаться с ошибкой EAGAIN, если системе не удаётся выделить внутренние ресурсы ядра, вместо ошибки ENOMEM как это происходит в Linux. В POSIX допускается такое поведение. Переносимые программы должны ожидать EAGAIN в цикле, как для EINTR.

В некоторых реализациях определена нестандартная константа INFTIM со значением -1 для использования в качестве значения timeout в poll(). Эта константа отсутствует в glibc.

Обсуждение того, что может случиться, если файловый дескриптор отслеживается poll() и при этом закрывается в другой нити, смотрите в select(2).

Отличия между библиотекой C и ядром

В Linux системный вызов ppoll() изменяет свой аргумент tmo_p. Однако, обёрточная функция glibc скрывает это поведение с помощью локальной переменной для аргумента timeout, которая передаётся в системный вызов. Поэтому glibc функция ppoll() не изменяет свой аргумент tmo_p.

Ядерный системный вызов ppoll() имеет пятый аргумент, size_t sigsetsize, в котором указывается размер аргумента sigmask в байтах. В обёрточной функции glibc ppoll() в этом аргументе передаётся постоянная величина (равная sizeof(kernel_sigset_t)). Описание различий sigset между ядерным и библиотечным вызовом смотрите в sigprocmask(2).

ДЕФЕКТЫ

Смотрите описание ложных уведомлений о готовности в разделе ДЕФЕКТЫ справочной страницы select(2).

ПРИМЕРЫ

The program below opens each of the files named in its command-line arguments and monitors the resulting file descriptors for readiness to read (POLLIN). The program loops, repeatedly using poll() to monitor the file descriptors, printing the number of ready file descriptors on return. For each ready file descriptor, the program:

  • displays the returned revents field in a human-readable form;
  • if the file descriptor is readable, reads some data from it, and displays that data on standard output; and
  • if the file descriptors was not readable, but some other event occurred (presumably POLLHUP), closes the file descriptor.

Suppose we run the program in one terminal, asking it to open a FIFO:


$ mkfifo myfifo
$ ./poll_input myfifo

In a second terminal window, we then open the FIFO for writing, write some data to it, and close the FIFO:


$ echo aaaaabbbbbccccc > myfifo

In the terminal where we are running the program, we would then see:


Opened "myfifo" on fd 3
About to poll()
Ready: 1

fd=3; events: POLLIN POLLHUP
read 10 bytes: aaaaabbbbb About to poll() Ready: 1
fd=3; events: POLLIN POLLHUP
read 6 bytes: ccccc About to poll() Ready: 1
fd=3; events: POLLHUP
closing fd 3 All file descriptors closed; bye

In the above output, we see that poll() returned three times:

  • On the first return, the bits returned in the revents field were POLLIN, indicating that the file descriptor is readable, and POLLHUP, indicating that the other end of the FIFO has been closed. The program then consumed some of the available input.
  • The second return from poll() also indicated POLLIN and POLLHUP; the program then consumed the last of the available input.
  • On the final return, poll() indicated only POLLHUP on the FIFO, at which point the file descriptor was closed and the program terminated.

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

/* poll_input.c

Licensed under GNU General Public License v2 or later. */ #include <poll.h> #include <fcntl.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0) int main(int argc, char *argv[]) {
int nfds, num_open_fds;
struct pollfd *pfds;
if (argc < 2) {
fprintf(stderr, "Usage: %s file...\n", argv[0]);
exit(EXIT_FAILURE);
}
num_open_fds = nfds = argc - 1;
pfds = calloc(nfds, sizeof(struct pollfd));
if (pfds == NULL)
errExit("malloc");
/* Open each file on command line, and add it 'pfds' array */
for (int j = 0; j < nfds; j++) {
pfds[j].fd = open(argv[j + 1], O_RDONLY);
if (pfds[j].fd == -1)
errExit("open");
printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);
pfds[j].events = POLLIN;
}
/* Keep calling poll() as long as at least one file descriptor is
open */
while (num_open_fds > 0) {
int ready;
printf("About to poll()\n");
ready = poll(pfds, nfds, -1);
if (ready == -1)
errExit("poll");
printf("Ready: %d\n", ready);
/* Deal with array returned by poll() */
for (int j = 0; j < nfds; j++) {
char buf[10];
if (pfds[j].revents != 0) {
printf(" fd=%d; events: %s%s%s\n", pfds[j].fd,
(pfds[j].revents & POLLIN) ? "POLLIN " : "",
(pfds[j].revents & POLLHUP) ? "POLLHUP " : "",
(pfds[j].revents & POLLERR) ? "POLLERR " : "");
if (pfds[j].revents & POLLIN) {
ssize_t s = read(pfds[j].fd, buf, sizeof(buf));
if (s == -1)
errExit("read");
printf(" read %zd bytes: %.*s\n",
s, (int) s, buf);
} else { /* POLLERR | POLLHUP */
printf(" closing fd %d\n", pfds[j].fd);
if (close(pfds[j].fd) == -1)
errExit("close");
num_open_fds--;
}
}
}
}
printf("All file descriptors closed; bye\n");
exit(EXIT_SUCCESS); }

СМ. ТАКЖЕ

restart_syscall(2), select(2), select_tut(2), epoll(7), time(7)

ЗАМЕЧАНИЯ

Эта страница является частью проекта Linux man-pages версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу https://www.kernel.org/doc/man-pages/.

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан Alexey, Azamat Hackimov <azamat.hackimov@gmail.com>, kogamatranslator49 <r.podarov@yandex.ru>, Kogan, Max Is <ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

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

11 апреля 2020 г. Linux