PROCESS_VM_READV(2)

名前
process_vm_readv, process_vm_writev - プロセスのアドレス空間間でデータを転送する

書式
#include <sys/uio.h>
ssize_t process_vm_readv(pid_t pid,
                         const struct iovec *local_iov,
                         unsigned long liovcnt,
                         const struct iovec *remote_iov,
                         unsigned long riovcnt,
                         unsigned long flags);
ssize_t process_vm_writev(pid_t pid,
                          const struct iovec *local_iov,
                          unsigned long liovcnt,
                          const struct iovec *remote_iov,
                          unsigned long riovcnt,
                          unsigned long flags);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

process_vm_readv(), process_vm_writev():
    _GNU_SOURCE

説明
これらのシステムコールは、 呼び出し元プロセス (「ローカルプロセス」) と pid で指定されるプロセス (「リモートプロセス」) のアドレス空間間でデータを転送する。 データの移動は、 カーネル空間を経由することなく、 2 つのプロセスのアドレス空間間で直接行われる。 process_vm_readv() システムコールは、 リモートプロセスからローカルプロセスへデータを転送する。 転送対象のデータは remote_iov と riovcnt で指定される。 remote_iov はプロセス pid におけるアドレス範囲を指定する配列へのポインターで、 riovcnt は remote_iov の要素数を指定する。 データは local_iov と liovcnt で指定された場所に転送される。 local_iov は呼び出し元プロセスにおけるアドレス範囲を指定する配列で、 liovcnt は local_iov の要素数を指定する。 process_vm_writev() システムコールは process_vm_readv() の逆で、 ローカルプロセスからリモートプロセスにデータを転送する。 転送の方向が違う以外は、 引き数 liovcnt, local_iov, riovcnt, remote_iov は process_vm_readv() と同じ意味を持つ。 引き数 local_iov と remote_iov は iovec 構造体の配列へのポイン タである。 iovec 構造体は <sys/uio.h> で以下のように定義 されている:
struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};
バッファーは配列の順序で処理される。 つまり、 process_vm_readv() は local_iov[0] が一杯になるまでデータを詰めてから、 local_iov[1] に進むことを意味する。 同様に、 remote_iov[0] を全部読み出してから remote_iov[1] に進み、 以降も同様である。 同様に、 process_vm_writev() は local_iov[0] の内容を全部読み出してから local_iov[1] に進み、 書き込み先でも remote_iov[0] が一杯になってから remote_iov[1] に進む。 長さ remote_iov[i].iov_len と local_iov[i].iov_len は同じである必要はない。 したがって、 ローカル側で 1 つのバッファーのデータがリモート側で複数のバッファーに分割されることがあるし、 その逆も起こりえる。 flags 引き数は現在使用されておらず、 0 を設定しなければならない。 liovcnt と riovcnt で指定される値は IOV_MAX 以下でなければならない (IOV_MAX は <limits.h> で定義されており、 sysconf(_SC_IOV_MAX) の呼び出しでも入手できる)。 要素数引き数と local_iov のチェックは、 すべてのデータ転送に先立って行われる。 要素数が大きすぎる場合や local_iov が無効な場合、 アドレスがローカルプロセスがアクセスできない領域を参照している場合は、 配列のどの要素も処理されず、 すぐにエラーが返される。 ただし、 これらのシステムコールは、 実際に読み出し/書き込みを行う直前までリモートプロセスのメモリー領域のチェックを行わない点に注意すること。 結果として、 remote_iov の要素の一つがリモートプロセスで無効なメモリー領域を参照している場合、 部分的な読み出し/書き込み (「返り値」の節を参照) が行われることになる。 これ以降は読み出し/書き込みは行われない。 リモートプロセスから長さ不明のデータ (例えば NULL 終端された C 文字列) を読み出す際で、 リモート側の一つの iovec 要素が複数のメモリーページ (通常は 4KiB) にまたがらないようにしている場合は、 この点に注意が必要である。 (リモートからの読み出しを 2 つの remote_iov 要素に分割し、 1 つの local_iov 要素への書き込みにマージすればよい。 最初の読み出しでページ境界まで読み出し、 次の読み出しを次のページ境界から行う。) 他のプロセスからの読み出しや他のプロセスへの書き込みを行うには、 呼び出し元がケーパビリティ CAP_SYS_PTRACE を持っていなければならない、もしくは、 リモートプロセスの実ユーザー ID、 実効ユーザー ID、 保存 set-user-ID が呼び出し元の実ユーザー ID と一致し、 かつリモートプロセスの実グループ ID、 実効グループ ID、 保存 set-group-ID が呼び出し元の実グループ ID と一致していなければならない。 (ここで必要なアクセス許可は、 リモートプロセスに対して ptrace(2) の PTRACE_ATTACH を実行するのに必要な許可と全く同じである。)

返り値
成功すると、 process_vm_readv() は読み出したバイト数を返し、 process_vm_writev() は書き込んだバイト数を返す。 この返り値は、 読み出し/書き込みが部分的に行われた場合には、 要求された総バイト数よりも小さくなることがある (部分的な転送は iovec 要素単位に行われ、 これらのシステムコールが一つの iovec 要素の一部だけが転送されることはない)。 呼び出し元は返り値を検査して、 部分的な読み出し/書き込みが起こったかどうかを判定できる。 エラーの場合は -1 が返され、 errno が適切に設定される。

エラー

EINVAL
    local_iov か remote_iov のいずれかの iov_len の合計値が ssize_t で表現できる値を超えている。

EINVAL
    flags が 0 でない。

EINVAL
    liovcnt か riovcnt が大きすぎる。

EFAULT
    local_iov で指定されたメモリーが呼び出し元がアクセス可能なアドレス空間の外にある。

EFAULT
    remote_iov で指定されたメモリーがプロセス pid がアクセス可能なアドレス空間の外にある。

ENOMEM
    iovec 構造体の内部コピーのためのメモリーを割り当てできなかった。

EPERM
    呼び出し側がプロセス pid のアドレス空間に対するアクセス許可を 持っていない。

ESRCH
    ID が pid のプロセスが存在しない。

バージョン
これらのシステムコールは Linux 3.2 で追加された。ライブラリによる サポートは glibc バージョン 2.15 以降で提供されている。

準拠
これらのシステムコールは非標準で Linux による拡張である。

注意
process_vm_readv() と process_vm_writev() により実行されるデータ転送をどのように行ったとしても、 これらがアトミックに行われる保証はない。 これらのシステムコールは、 (共有メモリーやパイプなどを使った場合に必要となる 2 回のコピーではなく) 1 回のコピー処理でメッセージの交換を許すことで、 高速なメッセージ送信をできるようにするために設計された。

例
以下のサンプルコードは process_vm_readv() の使用例を示すものである。 このコードは PID 10 のプロセスのアドレス 0x10000 から 20 バイトを読み取り、 最初の 10 バイトを buf1 に、 残りの 10 バイトを buf2 に書き込む。

#include <sys/uio.h>
int
main(void)
{
    struct iovec local[2];
    struct iovec remote[1];
    char buf1[10];
    char buf2[10];
    ssize_t nread;
    pid_t pid = 10;             /* PID of remote process */
    local[0].iov_base = buf1;
    local[0].iov_len = 10;
    local[1].iov_base = buf2;
    local[1].iov_len = 10;
    remote[0].iov_base = (void *) 0x10000;
    remote[0].iov_len = 20;
    nread = process_vm_readv(pid, local, 2, remote, 1, 0);
    if (nread != 20)
        return 1;
    else
        return 0;
}

関連項目
readv(2), writev(2)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。