readv(2) | System Calls Manual | readv(2) |
ИМЯ
readv, writev, preadv, pwritev, preadv2, pwritev2 - читает или пишет данные в несколько буферов
БИБЛИОТЕКА
Стандартная библиотека языка C (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);
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() и pwritev()
В системном вызове preadv() объединены возможности readv() и pread(2). Он выполняет ту же задачу что и readv(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию чтения.
В системном вызове pwritev() объединены возможности readv() и pwrite(2). Он выполняет ту же задачу что и writev(), но имеет четвёртый аргумент offset, задающий файловое смещение, по которому нужно выполнить операцию записи.
Файловое смещение не изменяется данными вызовами. Файл, заданный в fd, должен позволять изменение смещения.
preadv2() и pwritev2()
Данные системные вызовы подобны preadv() и pwritev(), но имеют дополнительный пятый аргумент flags, который изменяет поведение в зависимости от вызова.
В отличие от preadv() и pwritev(), если аргумент offset равен -1, то текущее файловое смещение используется и обновляется.
Аргумент flags содержит побитовое ИЛИ нуля и более следующих флагов:
- RWF_DSYNC (начиная с Linux 4.7)
- Эквивалентен флагу O_DSYNC для open(2), но действующий в конкретной операции записи. Этот флаг имеет смысл только для pwritev2(), и его действие распространяется только на диапазон данных, записываемым системным вызовом.
- RWF_HIPRI (начиная с Linux 4.6)
- Высокоприоритетное чтение/запись. Позволяет в файловых системах на основе блоков использовать опрос устройства с низкой задержкой, но с возможностью использовать дополнительные ресурсы (в настоящий момент это свойство работает только для файлового дескриптора, открытого с флагом O_DIRECT).
- RWF_SYNC (начиная с Linux 4.7)
- Эквивалентен флагу O_SYNC для open(2), но действующий в конкретной операции записи. Этот флаг имеет смысл только для pwritev2(), и его действие распространяется только на диапазон данных, записываемым системным вызовом.
- RWF_NOWAIT (начиная с Linux 4.14)
- 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().
- RWF_APPEND (начиная с Linux 4.16)
- Предоставляет эквивалент флага 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). Дополнительно определены следующие ошибки:
- EINVAL
- Сумма значений iov_len превышает значение ssize_t.
- EINVAL
- Количество векторов iovcnt меньше нуля или больше разрешённого максимума.
- EOPNOTSUPP
- В flags указан неизвестный флаг.
ВЕРСИИ
Отличия между библиотекой C и ядром
Объявления системных вызовов preadv() и pwritev() немного отличаются от им соответствующих обёрточных функций библиотеки GNU C; они показаны в ОБЗОРЕ. Последний аргумент, offset, раскладывается обёрточными функциями на два для системных вызовов:
unsigned long pos_l, unsigned long pos
В этих аргументах содержатся старшая и младшая 32-битная часть offset, соответственно.
СТАНДАРТЫ
ИСТОРИЯ
preadv(), pwritev(): Linux 2.6.30, glibc 2.10.
preadv2(), pwritev2(): Linux 4.6, glibc 2.26.
Исторические отличия между библиотекой 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.
ПРИМЕЧАНИЯ
Согласно POSIX1, в реализации можно устанавливать ограничение на количество элементов, которые можно передать в iov. Реализация может объявить это ограничение в IOV_MAX (в файле <limits.h>) или во время выполнения в виде возвращаемого значения sysconf(_SC_IOV_MAX). В современных Linux данное ограничение равно 1024. В времена Linux 2.0 оно было равно 16.
ОШИБКИ
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);
СМОТРИТЕ ТАКЖЕ
ПЕРЕВОД
Русский перевод этой страницы руководства разработал(и) 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 (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
15 июня 2024 г. | Справочные страницы Linux 6.9.1 |