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);
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 содержит побитовое ИЛИ нуля и более следующих флагов:
При успешном выполнении readv(), preadv() и preadv2() возвращается количество считанных байт; вызовы writev(), pwritev() and pwritev2() возвращают количество записанных байт.
Заметим, что для успешного выполнения не считается ошибкой передача меньшего количества байт чем запрошено (смотрите read(2) и write(2)).
В случае ошибки возвращается -1, а errno устанавливается в значение ошибки.
Вызовы могут возвращать те же ошибки что и read(2) и write(2). Кроме этого, preadv(), preadv2(), pwritev() и pwritev2() также могут завершаться с ошибками как у lseek(2). Дополнительно определены следующие ошибки:
Вызовы 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.
Объявления системных вызовов preadv() и pwritev() немного отличаются от им соответствующих обёрточных функций библиотеки GNU C; они показаны в ОБЗОРЕ. Последний аргумент, offset, раскладывается обёрточными функциями на два для системных вызовов:
unsigned long pos_l, unsigned long pos
В этих аргументах содержатся старшая и младшая 32-битная часть offset, соответственно.
Для учёта того, что значение 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);
Русский перевод этой страницы руководства был сделан 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 |