Provided by: manpages-ja-dev_0.5.0.0.20161015+dfsg-1_all 

名前
readv, writev, preadv, pwritev - 複数のバッファーへの読み書きを行なう
書式
#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);
glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
preadv(), pwritev(): _BSD_SOURCE
説明
readv() システムコールは、ファイルディスクリプター fd に関連付けられた ファイルから、 iovcnt 個のバッ
ファー分のデータを読み込み、 iov で指定 されたバッファーに格納する ("scatter input";「ばらまき入力」)。
writev() システムコールは、 iov で指定されたバッファーから最大 iovcnt 個のバッファー分のデータを取り出
し、 ファイルディスクリプター fd に関連付けら れたファイルに書き込む ("gather output";「かき集め出力」)。
ポインター iov は iovec 構造体の配列へのポインターである。 iovec 構造体は <sys/uio.h> で以下のように定義
されている:
struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
readv() システムコールは、複数のバッファーにデータを読み込む点を除いて read(2) と全く同様の動作を行う。
writev() システムコールは、複数のバッファーのデータを書き出す点以外は write(2) と全く同様の動作を行う。
バッファーは配列の順序で処理される。これは、 readv() が iov[0] が完全に一杯になるまでデータを詰めてか
ら、 iov[1] などに進むことを意味する (データが十分ない場合は、 iov が指すバッファーのいずれも一杯にならな
い)。 同様に、 writev() は iov[0] の内容を全部書き出してから iov[1] などに進む。
readv() と writev() によるデータ転送は atomic に行われる。つまり、 writev() によるデータ書き込みは一つ
のブロックとして行われ、他のプロセスの write による書き込みと混ざり合うことはない (例外に関しては pipe(7)
を参照のこと)。同様に、 readv() はファイルから連続するデータブロックが読み出すことが保証され、 同じファ
イル記述 (file description; open(2) 参照) を参照するファイルディスクリプターを持つ他のスレッドやプロセス
が 実行した read 操作の影響を受けることはない。
preadv() と pwritev()
preadv() システムコールは readv() と preadv(2) の機能を 組み合わせたものである。 readv() と同じ処理を実行
するが、 4 番目の引き数 offset が追加されており、 この引き数は入力操作を行うファイルオフセットを指定す
る。
pwritev() システムコールは writev() と pwrite(2) の機能を 組み合わせたものである。 writev() と同じ処理を
実行するが、 4 番目の引き数 offset が追加されており、 この引き数は出力操作を行うファイルオフセットを指定
する。
これらのシステムコールで、ファイルオフセットは変更されない。 fd が参照するファイルは seek 可能でなければ
ならない。
返り値
成功した場合、 readv() と preadv は読み込んだバイト数を返し、 writev() と pwritev()は書き込んだバイト数を
返す。 エラーの場合 -1 を返し、errno を適切に設定する。
エラー
read(2) や write(2) と同じエラーが定義されている。 さらに、 preadv() と pwritev() は lseek(2) と同じ理
由でも失敗する。 また、追加で以下のエラーが定義されている:
EINVAL iov_len の合計が ssize_t の範囲をオーバーフローした。
EINVAL ベクタ数 iovcnt が 0 より小さいか許可された最大値よりも大きかった。
バージョン
preadv() と pwritev() は Linux 2.6.30 で初めて登場した。 ライブラリによるサポートは glibc 2.10 で追加され
た。
準拠
readv(), writev(): 4.4BSD (これらのシステムコールは 4.2BSD で初めて登場した), POSIX.1-2001.
preadv(), pwritev(): 非標準だが、最近の BSD にも存在する。
注意
POSIX.1-2001 では、 iov で渡すことができる要素数に上限を設ける実装が認められている。 実装はこの上限値を広
告することができ、 <limits.h> の IOV_MAX を定義することや、 実行時に sysconf(_SC_IOV_MAX) の返り値経由で
知ることができる。 最近の Linux では、 この上限値は 1024 である。 Linux 2.0 の頃は、 この値は 16 であっ
た。
C ライブラリとカーネル ABI の違い
素のシステムコール preadv() と pwritev() のシグネチャーは、 「書式」に書かれている対応する GNU C ライブラ
リのラッパー関数のものとは少し異なる。 最後の引き数 offset はラッパー関数によりシステムコールの 2 つの引
き数に展開される。
unsigned long pos_l, unsigned long pos
これらの引き数は、それぞれ、 offset の下位 32 ビットと上位 32 ビットである。
以前の C ライブラリとカーネル ABI の違い
古いバージョンの Linux では IOV_MAX が非常に小さかったという事実に対処するため、 glibc の readv() と
writev() のラッパー関数は、 その関数の内部で呼ばれるカーネルシステムコールがこの上限を超過して失敗したこ
とを検出すると、 追加の動作をしていた。 readv() の場合、 ラッパー関数は iov で指定された全ての要素を格納
できる大きさの一時バッファーを割り当て、 read(2) を呼び出す際にそのバッファーを渡し、 そのバッファーの
データを iov の各要素の iov_base フィールドが指定する場所にコピーしてから、 そのバッファーを解放してい
た。 writev() のラッパー関数も、 同じように一時バッファーを使って write(2) を呼び出していた。
glibc ラッパー関数でのこの追加の動作は Linux 2.2 以降では必要なくなった。 しかし、 glibc はバージョン
2.10 まではこの動作を続けていた。 glibc 2.9 以降では、 システムがバージョン 2.6.18 より前の Linux カーネ
ル (2.6.18 は勝手に選択したカーネルバージョンである) を実行しているとライブラリが検出した場合にのみ、
ラッパー関数はこの動作を行う。 glibc 2.20 以降では、 (Linux カーネルのバージョン 2.6.32 以降が必須条件と
なり) glibc のラッパー関数は常にシステムコールを直接呼び出すようになっている。
バグ
ファイルディスクリプターに対する操作を行う readv() や writev() と、 標準入出力ライブラリの関数をごちゃま
ぜにして呼ぶのはお薦めしない。 どんな結果になるかは定義されておらず、おそらく期待する結果は 得られないだ
ろう。
例
以下のサンプルコードは 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);
関連項目
pread(2), read(2), write(2)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告
に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。
Linux 2015-01-22 READV(2)