Provided by: manpages-ja-dev_0.5.0.0.20180315+dfsg-1_all ![bug](/img/bug.png)
![bug](/img/bug.png)
名前
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/ に書かれている。