メモリ操作に関するシステムコールのサンプルコード (C 言語)
[履歴] [最終更新] (2018/08/20 21:35:05)

概要

メモリ操作に関するシステムコールを利用した C 言語のサンプルコードを記載します。

ページサイズの確認 (getpagesize)

OS はメモリを複数のページに分割して管理しています。一つのページのサイズは以下のコマンドで確認できます。通常は 4kb です。

$ getconf PAGESIZE
4096

システムコール getpagesize を利用して上記値を取得できます。

#include <unistd.h>
#include <stdio.h>

int main() {
    printf("%d\n", getpagesize());
    return 0;
}

バッファ用の変数を利用せずにファイルディスクリプタからデータを読み出す (mmap/munmap)

open 等で用意したファイルディスクリプタ経由でデータを読み出して、バッファ用の変数にコピーするためには read を利用できます。そうではなく、ファイル自体をメモリに貼り付けることでデータを読み出すこともできます。メモリ内に別途バッファ用の変数を用意する必要もありません。ただし、read と比較して I/O の発生タイミングについては制御が困難です。

#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd_r = 0; // 標準入力をメモリに貼り付けてみます。
    int fd_w = 1; // 標準出力

    int pagesize; // ページサイズ
    int filesize; // 標準入力のファイルサイズ
    int p; // ファイルポインタ
    char *mp; // メモリに貼り付けられたファイルへのポインタ

    // ページサイズの取得
    pagesize = getpagesize();

    // ファイルサイズの取得 (ファイル終端まで進めてファイル先頭からのオフセットを取得)
    if((filesize = lseek(fd_r, 0, SEEK_END)) < 0) {
        perror("lseek failed");
        return 1;
    }

    // ここでは、標準入力の一部だけをメモリに貼り付けてループする実装とします。
    for(p = 0; p < filesize; p += pagesize) {
        if(filesize < p + pagesize) {
            pagesize = filesize - p; // ループの最後のみ微調整
        }
        // 読み込み専用でメモリに貼り付けます。
        if((mp = mmap(0, pagesize, PROT_READ, MAP_PRIVATE, fd_r, p)) == MAP_FAILED) {
            perror("mmap failed");
            return 1;
        }
        write(fd_w, mp, pagesize);
        if(munmap(mp, pagesize) < 0) { // メモリを解放します。
            perror("munmap failed");
            return 1;
        }
    }
    return 0;
}

実行例 (echo コマンドをコピーしています)

$ gcc -Wall -O2 main.c && ./a.out < /bin/echo > myecho
$ md5sum /bin/echo
40c0d2f7bd3e35325bc04b332987272a  /bin/echo
$ md5sum myecho 
40c0d2f7bd3e35325bc04b332987272a  myecho
関連ページ