メモリ操作に関するシステムコールを利用した C 言語のサンプルコードを記載します。
OS はメモリを複数のページに分割して管理しています。一つのページのサイズは以下のコマンドで確認できます。通常は 4kb です。
$ getconf PAGESIZE
4096
システムコール getpagesize
を利用して上記値を取得できます。
#include <unistd.h>
#include <stdio.h>
int main() {
printf("%d\n", getpagesize());
return 0;
}
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