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 が無効な場合、 アドレスがローカルプロセスがアクセスできない領域を参照している場合は、 配列のどの要素も処理されず、 すぐにエラーが返される。

Note, however, that these system calls do not check the memory regions in the remote process until just before doing the read/write. Consequently, a partial read/write (see RETURN VALUE) may result if one of the remote_iov elements points to an invalid memory region in the remote process. No further reads/writes will be attempted beyond that point. Keep this in mind when attempting to read data of unknown length (such as C strings that are null-terminated) from a remote process, by avoiding spanning memory pages (typically 4 KiB) in a single remote iovec element. (Instead, split the remote read into two remote_iov elements and have them merge back into a single write local_iov entry. The first read entry goes up to the page boundary, while the second starts on the next page boundary.)

Permission to read from or write to another process is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check; see ptrace(2).

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

エラーの場合は -1 が返され、 errno が適切に設定される。

エラー

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

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

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

EINVAL
    flags が 0 でない。

EINVAL
    liovcnt か riovcnt が大きすぎる。

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 プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。