DOKK / manpages / debian 12 / manpages-ru-dev / preadv.2.ru
readv(2) System Calls Manual readv(2)

ИМЯ

readv, writev, preadv, pwritev, preadv2, pwritev2 - читает или пишет данные в несколько буферов

Standard C library (libc, -lc)

СИНТАКСИС

#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);
ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

preadv(), pwritev():


Начиная с glibc 2.19:
_DEFAULT_SOURCE
В версии glibc 2.19 и более ранних:
_BSD_SOURCE

ОПИСАНИЕ

Системный вызов readv() считывает iovcnt буферов из файла, связанного с файловым дескриптором fd, в буферы, описываемые iov («разнесённый ввод»).

Системный вызов writev() записывает iovcnt буферов, описанных iov, в файл, связанный с файловым дескриптором fd («сборный вывод»).

The pointer iov points to an array of iovec structures, described in iovec(3type).

Системный вызов readv() работает также как read(2), но считывает несколько буферов.

Системный вызов writev() работает также как write(2), но записывает несколько буферов.

Буферы выбираются в порядке, в каком они указаны в массиве. Это означает, что readv() сначала полностью заполнит iov[0], и только потом перейдёт к iov[1], и так далее. (Если данных недостаточно, то могут быть заполнены не все буферы, на которые указывает iov.) Подобным образом writev() запишет сначала всё содержимое iov[0], затем iov[1], и так далее.

Выполняемые вызовами readv() и writev() пересылки данных атомарны: данные записываются writev() единичным блоком, который не перемешивается с выводом других процессов; аналогично, readv() гарантированно считывает непрерывный блок данных из файла, независимо от операций чтения из других нитей или процессов, которые имеют файловые дескрипторы, ссылающиеся на это же открытое файловое описание (см. open(2)).

В системном вызове preadv() объединены возможности readv() и pread(2). Он выполняет ту же задачу что и readv(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию чтения.

В системном вызове pwritev() объединены возможности readv() и pwrite(2). Он выполняет ту же задачу что и writev(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию записи.

Файловое смещение не изменяется данными вызовами. Файл, заданный в fd, должен позволять изменение смещения.

Данные системные вызовы подобны preadv() и pwritev(), но имеют дополнительный пятый аргумент flags, который изменяет поведение в зависимости от вызова.

В отличие от preadv() и pwritev(), если аргумент offset равен -1, то текущее файловое смещение используется и обновляется.

Аргумент flags содержит побитовое ИЛИ нуля и более следующих флагов:

Эквивалентен флагу O_DSYNC для open(2), но действующий в конкретной операции записи. Этот флаг имеет смысл только для pwritev2(), и его действие распространяется только на диапазон данных, записываемым системным вызовом.
Высокоприоритетное чтение/запись. Позволяет в файловых системах на основе блоков использовать опрос устройства с низкой задержкой, но с возможностью использовать дополнительные ресурсы (в настоящий момент это свойство работает только для файлового дескриптора, открытого с флагом O_DIRECT).
Эквивалентен флагу O_SYNC для open(2), но действующий в конкретной операции записи. Этот флаг имеет смысл только для pwritev2(), и его действие распространяется только на диапазон данных, записываемым системным вызовом.
Do not wait for data which is not immediately available. If this flag is specified, the preadv2() system call will return instantly if it would have to read data from the backing storage or wait for a lock. If some data was successfully read, it will return the number of bytes read. If no bytes were read, it will return -1 and set errno to EAGAIN (but see BUGS). Currently, this flag is meaningful only for preadv2().
Предоставляет эквивалент флага O_APPEND для open(2) для каждой записи. Данный флаг значим только для pwritev2(), и его действие проявляется только для диапазона данных, записанных системным вызовом. Аргумент offset не учитывается при операции записи; данные всегда добавляются в конец файла. Однако, если аргумент offset равен -1, то обновляется текущее смещение файла.

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

При успешном выполнении readv(), preadv() и preadv2() возвращается количество считанных байт; вызовы writev(), pwritev() and pwritev2() возвращают количество записанных байт.

Заметим, что для успешного выполнения не считается ошибкой передача меньшего количества байт чем запрошено (смотрите read(2) и write(2)).

В случае ошибки возвращается -1, а errno устанавливается в значение ошибки.

ОШИБКИ

Вызовы могут возвращать те же ошибки что и read(2) и write(2). Кроме этого, preadv(), preadv2(), pwritev() и pwritev2() также могут завершаться с ошибками как у lseek(2). Дополнительно определены следующие ошибки:

Сумма значений iov_len превышает значение ssize_t.
Количество векторов iovcnt меньше нуля или больше разрешённого максимума.
В flags указан неизвестный флаг.

ВЕРСИИ

Вызовы preadv() и pwritev() впервые появились в Linux 2.6.30; поддержка в библиотеке добавлена в glibc 2.10.

Вызовы preadv2() и pwritev2() впервые появились в Linux 4.6. Поддержка в библиотеке glibc добавлена в версии 2.26.

СТАНДАРТЫ

readv(), writev(): POSIX.1-2001, POSIX.1-2008, 4.4BSD (данные системные вызовы впервые появились в 4.2BSD).

preadv(), pwritev(): нет в стандарте, но есть в современных BSD.

preadv2(), pwritev2(): нестандартные расширения Linux.

ЗАМЕЧАНИЯ

Согласно POSIX1, в реализации можно устанавливать ограничение на количество элементов, которые можно передать в iov. Реализация может объявить это ограничение в IOV_MAX (в файле <limits.h>) или во время выполнения в виде возвращаемого значения sysconf(_SC_IOV_MAX). В современных Linux данное ограничение равно 1024. В времена Linux 2.0 оно было равно 16.

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

Объявления системных вызовов preadv() и pwritev() немного отличаются от им соответствующих обёрточных функций библиотеки GNU C; они показаны в ОБЗОРЕ. Последний аргумент, offset, раскладывается обёрточными функциями на два для системных вызовов:

unsigned long pos_l, unsigned long pos

В этих аргументах содержатся старшая и младшая 32-битная часть offset, соответственно.

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

Для учёта того, что значение IOV_MAX было мало в старых версиях Linux, обёрточные функции glibc readv() и writev() выполняют дополнительные действия, если обнаруживается, что используемый системный вызов ядра завершился неудачно из-за превышения этого ограничения. В случае readv(), обёрточная функция выделяет временный буфер, достаточный для всех элементов, указанных в iov, передаёт этот буфер в вызов read(2), копирует данные из буфера в места, указанные в полях iov_base элемента iov, а затем освобождает буфер. Обёрточная функция writev() выполняет аналогичную задачу с помощью временного буфера и вызова write(2).

The need for this extra effort in the glibc wrapper functions went away with Linux 2.2 and later. However, glibc continued to provide this behavior until glibc 2.10. Starting with glibc 2.9, the wrapper functions provide this behavior only if the library detects that the system is running a Linux kernel older than Linux 2.6.18 (an arbitrarily selected kernel version). And since glibc 2.20 (which requires a minimum of Linux 2.6.32), the glibc wrapper functions always just directly invoke the system calls.

ДЕФЕКТЫ

Linux 5.9 and Linux 5.10 have a bug where preadv2() with the RWF_NOWAIT flag may return 0 even when not at end of file.

ПРИМЕРЫ

Следующий пример кода демонстрирует использование writev():


char          *str0 = "hello ";
char          *str1 = "world\n";
ssize_t       nwritten;
struct iovec  iov[2];
iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);
nwritten = writev(STDOUT_FILENO, iov, 2);

СМ. ТАКЖЕ

pread(2), read(2), write(2)

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан aereiae <aereiae@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Katrin Kutepova <blackkatelv@gmail.com>, Lockal <lockalsash@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Баринов Владимир и Иван Павлов <pavia00@gmail.com>

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

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

5 февраля 2023 г. Linux man-pages 6.03