Главная » 2017 » Ноябрь » 21 » man 2 readv
01:30
man 2 readv

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


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



ОБЗОР


#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 («сборный вывод»).

Указатель iov указывает на массив структур iovec (определён в <sys/uio.h>:

struct iovec {
void *iov_base; /* начальный адрес */
size_t iov_len; /* количество передаваемых байт */
};

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

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

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

выполняет ту же задачу что и 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(), и его действие
распространяется только на диапазон данных, записываемым системным вызовом.



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


При успешном выполнении 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 меньше нуля или больше разрешённого максимума.

EINVAL В flags указан неизвестный флаг.
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).

Потребность в дополнительных действиях в обёрточных функциях glibc пропала в Linux
2.2 и новее. Однако glibc продолжала так работать до версии 2.10. начиная с glibc
2.9, обёрточные функции так работают только, если библиотека обнаруживает, что
система работает с ядром Linux меньше 2.6.18 (произвольно выбранная версия ядра).
И начиная с glibc 2.20 (для которой требуется минимальная версия ядра Linux
2.6.32) обёрточные функции glibc всегда просто вызывают системные вызовы.



ПРИМЕР


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

char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;

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);

Просмотров: 373 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar