プロトタイプ
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
mmap
- この関数を呼び出すプロセスの仮想メモリ空間にメモリマップ領域を作成します。
- addr はメモリ マップの開始位置を指定します。これが NULL の場合、カーネルが割り当て (ページ サイズ アライメント) を担当します。
移植性を高めるために NULL を使用してください。
- addr が NULL でない場合、カーネルはこの値を推奨値 (ヒント) として使用します。
Linux では、ページの端に近いスペースがマッピングを作成するために選択されます (常に /proc/sys/vm/mmap_min_addr で指定された値以上)。
- addr で指定された場所にマッピングがすでに存在する場合、カーネルは新しいアドレスを選択します (必ずしも addr に関連しているわけではありません)。
- 戻り値は作成されたメモリマップのアドレスです。
- ファイル メモリ マップの内容 (匿名マッピングではなくファイル マッピング) は、fd で指定されたオブジェクトの内容で初期化されます。内容はオフセット (ページサイズ、sysconf(_SC_PAGE_SIZE) の整数倍) から始まり、長さは length です。 。
- mmap が戻ってきたので、fd を閉じることができます。
- prot (保護) は、メモリ マップの保護モードを指定します (ファイルのオープン モードと競合することはできません)。
オプションの値は、prot_none またはその他の OR の値です。
PROT_EXEC、PROT_READ、PROT_WRITE、PROT_NONE
- flags パラメータ:
1) このパラメータは、他のプロセス (同じメモリ領域のマッピング) またはマップされたファイルから見えるかどうかに関係なく、メモリ マッピングの内容の変更に影響します。
2)
MAP_SHARED: メモリ マップの変更は他のプロセスおよび基礎となるファイルに表示され、不明なフラグは無視されます。
MAP_SHARED_VALIDATE (Linux 4.15 以降、Linux 拡張機能) は、不明なフラグに遭遇したときにエラーが報告されることを除いて MAP_SHARED と同じです。システムのクラッシュ時のデータ損失を回避するには、MAP_SYNC とともに使用します。
MAP_PRIVATE: メモリ マップへの変更は、他のプロセスや基礎となるファイルには表示されません。
MAP_ANONYMOUS: ファイルをマップする必要はありません。メモリ領域は 0 に初期化されます。fd は無視できますが、互換性のために -1 に設定します (一部のシステムでは必須)。
MAP_FIXE: addr で指定されたアドレスにマップすることは必須です (addr はページ位置合わせされている必要があります)。カーネル、libc などのバージョンによってメモリ レイアウトが異なるため、このオプションの使用には注意してください。
MAP_NORESERVE: メモリ マッピング用にスワップ領域を予約しません。物理メモリが枯渇すると、メモリ マップへの書き込みで SIGSEGV エラーが発生します。
マップを解除する
- addr で指定したメモリマッピングを削除すると、メモリマッピング範囲内のアドレスへの参照がすべて無効になります。
- プロセスが終了すると、メモリ マップは自動的にアンマップされます。
- addr はページ サイズに合わせなければなりませんが、length にはそのような要件はありません。
- 戻り値: 成功 - 0、失敗 -1 (errno)。
デモ
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
do {
perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1)
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
if (offset >= sb.st_size) {
fprintf(stderr, "offset is past end of file\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
} else {
length = sb.st_size - offset;
}
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
if (s != length) {
if (s == -1)
handle_error("write");
fprintf(stderr, "partial write");
exit(EXIT_FAILURE);
}
munmap(addr, length + offset - pa_offset);
close(fd);
exit(EXIT_SUCCESS);
}