MMAP

Section: Linux Programmer's Manual (2)
Updated: 2007-07-10
Index JM Home Page roff page
 

名前

mmap, munmap - ファイルやデバイスをメモリにマップ/アンマップする  

書式

#include <sys/mman.h>

void *mmap(void *start, size_t length, int prot, int flags,
           int fd, off_t offset);

int munmap(void *start, size_t length);
 

説明

mmap() は、新しいマッピングを呼び出し元プロセスの仮想アドレス空間に作成する。 新しいマッピングの開始アドレスは start で指定される。マッピングの長さは length 引き数で指定される。

start が NULL の場合、カーネルがマッピングを作成するアドレスを選択する。 この方法は最も移植性のある新しいマッピングの作成方法である。 start が NULL でない場合、カーネルはマッピングをどこに配置するかのヒントとして start を使用する。Linux では、マッピングは (アドレスが大きくなる方向で) すぐ次のページ境界に作成される。 新しいマッピングのアドレスは、呼び出しの返り値として返される。

ファイルマッピングの内容は、 ファイルディスクリプタ fd で参照されるファイル (もしくは他のオブジェクト) のオフセット offset から開始される length バイトのデータで初期化される (ファイルマッピングは無名マッピングの反対語である。 MAP_ANONYMOUS を参照)。 offsetsysconf(_SC_PAGE_SIZE) が返すページサイズの倍数でなければならない。

引き数 prot には、マッピングのメモリ保護をどのように行なうかを指定する (ファイルのオープンモードと矛盾してはいけない)。 prot には、 PROT_NONE か、以下のフラグをひとつ以上ビット毎の論理和 (OR) をとったものを 指定できる。

PROT_EXEC
ページは実行可能である。
PROT_READ
ページは読み込み可能である。
PROT_WRITE
ページに書き込み可能である。
PROT_NONE
ページにはアクセスできない。

flags 引き数により、マッピングに対する更新が同じ領域をマッピングしている 他のプロセスに見えるか、更新がマッピング元のファイルを通じて 伝えられるか、が決定される。この動作は、以下の値のいずれか一つだけ (複数は指定できない) を flags に含めることで指定する。

MAP_SHARED
このマッピングを共有する。 マッピングに対する更新はこのファイルをマッピングしている他のプロセス から見える。更新はマッピング元のファイルを通じて伝えられる。 ただし、ファイルの実際の更新は msync(2) または munmap(2) が呼ばれるまで行われないこともある。
MAP_PRIVATE
プライベートな copy-on-write (書き込み時コピー) マップを生成する。 マッピングに対する更新は同じファイルをマッピングしている他のプロセス には見えず、更新がマッピング元のファイルを通じて伝えられることもない。 mmap() の呼び出し後にマッピング元のファイルに対して行われた変更が、 マップ領域に反映されるかどうかは規定されていない。

上記の二つのフラグは POSIX.1-2001 で規定されている。

さらに、以下の値のうち 0 個以上をビット毎の論理和 (OR) で flags に指定することができる。

MAP_32BIT
マッピングをプロセスのアドレス空間の先頭 2GB の範囲に配置する。 MAP_FIXED がセットされている場合は、このフラグは無視される。 現在のところ、このフラグがサポートされているのは、x86-64 アーキテクチャ上 の 64 ビット・プログラムについてのみである。
MAP_ANON
MAP_ANONYMOUS の同義語。非推奨。
MAP_ANONYMOUS
マッピングはどのファイルとも関連付けされない。 マッピングの内容は 0 で初期化される。 引き数 fdoffset は無視される。 ただし、実装によっては MAP_ANONYMOUS (もしくは MAP_ANON) が指定された場合、 fd を -1 にする必要があり、 移植性が必要なアプリケーションでは必ず fd を -1 にすべきである。 MAP_ANONYMOUSMAP_SHARED を組み合わせての利用は カーネル 2.4 以降の Linux でのみサポートされている。
MAP_DENYWRITE
このフラグは無視される (ずっと前は、マップ元のファイルへの書き込みを行おうとすると、エラー ETXTBUSY で失敗するようにシグナルが設定されていたが、これは denial-of-service (サービス拒否) 攻撃の原因となった)。
MAP_EXECUTABLE
このフラグは無視される。
MAP_FILE
互換性のためのフラグ。無視される。
MAP_FIXED
start をアドレスのヒントとして使用するのではなく、 start で指定されたアドレスをそのまま使用してマッピングを配置する。 start はページサイズの倍数でなければならない。 startlen で指定されたメモリ領域が既存のマッピングのページと重なる場合、 既存のマッピングの重なった部分は捨てられる。 もし指定されたアドレスが使用できない場合、 mmap() は失敗する。 マッピングに対して固定アドレスを要求するのは移植性の面で劣るので、 このオプションは使用しないことを推奨する。
MAP_GROWSDOWN
スタック用に使用される。マッピングをメモリ内で逆向きに行うことを カーネル仮想メモリシステムに指示する。 (訳注:マッピングは通常はメモリ・アドレスが増加する向きに行うが、 このオプションを指定すると逆向きにマッピングを行う)
MAP_LOCKED (Linux 2.5.37 以降)
マップされた領域のページを mlock(2) の方法でメモリ内にロックする。 それ以前のカーネルでは、このフラグは無視される。
MAP_NONBLOCK (Linux 2.5.46 以降)
MAP_POPULATE と組み合わせた場合のみ意味を持つ。 read-ahead (前もって読み込むこと) を実行しない。 単に、すでに RAM 上に存在するページに対して ページテーブルエントリを作成するだけである。
MAP_NORESERVE
このマッピングに対するスワップ空間の予約を行わない。 スワップ空間を予約した場合は、このマッピングの変更が必ず可能なことが 保証される。予約を行わなかった場合、物理メモリに空きがないと 書き込み時に SIGSEGV エラーを受け取ることがある。 proc(5) の /proc/sys/vm/overcommit_memory ファイルについての議論も参照。 バージョン 2.6 より前のカーネルでは、このフラグは書き込み可能な プライベート・マッピングについてのみ効果があった。
MAP_POPULATE (Linux 2.5.46 以降)
ファイルを前もって読み込む (read-ahead) ことで、 ファイルマッピング用のページテーブルを配置 (populate) する (前もってページフォールトさせる (prefault))。 この後は、マッピングに対するアクセスがページフォールトで ブロックされなくなる。

上記のフラグの中では、 MAP_FIXED だけが POSIX.1-2001 で規定されている。 しかしながら、ほとんどのシステムで MAP_ANONYMOUS (またはその同義語である MAP_ANON) もサポートされている。

いくつかのシステムでは、上記以外にフラグとして MAP_AUTOGROW, MAP_AUTORESRV, MAP_COPY, MAP_LOCAL が規定されている。

mmap() によってマップされたメモリの属性は fork(2) の際に継承される。

ファイルはページサイズの整数倍の領域にマップされる。サイズがページサイズの 整数倍でないファイルの場合、マップ時に残りの領域は 0 で埋められ、この領域へ 書きこみを行ってもファイルに書き出されることはない。マッピングを行った元 ファイルのサイズを変更した場合、元ファイルの追加されたり削除された領域に対応 するマップされたページに対してどのような影響があるかは規定されていない。 システムコール munmap() は指定されたアドレス範囲のマップを消去し、 これ以降のその範囲内へのメモリ参照は不正となる。 この領域は、プロセスが終了したときにも自動的にアンマップされる。 一方、ファイル記述子をクローズしても、この領域はアンマップされない。

start アドレスはページサイズの整数倍でなければならない。指定された範囲の一部分を 含む全てのページはアンマップされ、これ以降にこれらのページへの参照があると SIGSEGV が発生する。 指定した範囲内にマップされたページが一つも含まれていない場合でも エラーにならない。 ファイルと関連付けられたマッピングの場合、マッピングされたファイルの st_atime フィールドは、 mmap() されてからアンマップ (unmap) されるまでの間に更新されることがある。 それまでに更新が行われていなければ、マップされたページへの最初の参照があった 際に更新される。

PROT_WRITEMAP_SHARED の両方を指定してマップされたファイルの場合、書き込みがあると、 st_ctimest_mtime の両フィールドは、マップされた領域への書き込みより後で、 MS_SYNC または MS_ASYNC フラグを指定して msync(2) が呼ばれる前までに更新される。  

返り値

mmap() は成功するとマップされた領域へのポインタを返す。 失敗すると値 MAP_FAILED (つまり (void *) -1) を返し、 errno がエラーの内容にしたがってセットされる。 munmap() は成功すると 0 を返す。失敗すると -1 を返し、 errno がセットされる (多くの場合 EINVAL になるだろう)。  

エラー

EACCES
以下のいずれかの場合。 ファイル記述子の参照先が通常のファイルではない (non-regular file) 。 MAP_PRIVATE を要求したが fd は読み込み用にオープンされていない。 MAP_SHARED を要求して PROT_WRITE をセットしたが fd は読み書きモード (O_RDWR) でオープンされていない、 PROT_WRITE をセットしたが、ファイルは追加 (append) 専用である。
EAGAIN
ファイルがロックされている。またはロックされているメモリが多すぎる (setrlimit(2) を参照)。
EBADF
fd が有効なファイル記述子 (file descriptor) ではない (かつ MAP_ANONYMOUS がセットされていない)。
EINVAL
startlengthoffset が適切でない (例えば、大きすぎるとか、ページ境界にアラインメントされていない)。
EINVAL
(Linux 2.6.12 以降) length が 0 であった。
EINVAL
flagsMAP_PRIVATEMAP_SHARED のどちらも含まれていなかった、もしくは その両方が含まれていた。
ENFILE
オープンされたファイルの総数がシステムの制限に達した。
ENODEV
指定されたファイルが置かれているファイルシステムがメモリマッピングをサポート していない。
ENOMEM
メモリに空きがない、または処理中のプロセスのマッピング数が最大数を超過した。
EPERM
prot 引き数は PROT_EXEC を行うように指定されているが、 no-exec でマウントされたファイルシステム上のファイルに マップ領域が対応している。
ETXTBSY
MAP_DENYWRITE がセットされているが fd で指定されているオブジェクトは書き込み用に開かれている。

マップ領域を利用する際に、以下のシグナルが発生することがある:

SIGSEGV
読み込み専用で mmap された領域へ書き込みを行おうとした。
SIGBUS
バッファのうち、ファイルに関連づけられていない部分 (例えばファイル末尾を越えた部分など。これには 他のプロセスがファイルを切り詰めた場合なども含まれる) にアクセスしようとした。
 

準拠

SVr4, 4.4BSD, POSIX.1-2001.  

可用性

mmap(), msync(2) munmap() が利用可能な POSIX システムでは、 _POSIX_MAPPED_FILES は <unistd.h> で 0 より大きな値に定義される (sysconf(3) も参照のこと)。  

注意

カーネル 2.4 以降、このシステムコールは mmap2(2) に取って代わられた。 現在では、 glibc の mmap() のラッパー関数は offset を適切に調整してから mmap2(2) を起動する。

(x86 などの) いくつかのアーキテクチャでは、 PROT_WRITE をセットすると、暗黙のうちに PROT_READ がセットされる。 PROT_READ をセットした際に暗黙のうちに PROT_EXEC がセットされるかどうかは、アーキテクチャ依存である。 移植性を考慮したプログラムでは、 新規にマップした領域でコードを実行したい場合は、常に PROT_EXEC をセットすべきである。  

バグ

Linux においては、上記の MAP_NORESERVE で述べられているような保証はない。 デフォルトでは、システムがメモリを使い切った場合には、 どのプロセスがいつ強制終了されるか分からないからである。

2.6.7 より前のカーネルでは、 protPROT_NONE が指定された場合にのみ、 MAP_POPULATE フラグが効力を持つ。

SUSv3 では、 length が 0 の場合、 mmap() は失敗すると規定されている。しかしながら、2.6.12 より前のカーネルでは、 この場合に mmap() は成功していた (マッピングは作成されず、 start が返されていた)。 カーネル 2.6.12 以降では、 mmap() はエラー EINVAL で失敗する。  

以下のプログラムは、一番目のコマンドライン引き数で指定された ファイルの一部を標準出力に表示する。 表示する範囲は、二番目、三番目のコマンドライン引き数で渡される オフセットと長さで指定される。 このプログラムは、指定されたファイルの必要なページのメモリ・ マッピングを作成し、 write(2) を使って所望のバイトを出力する。


#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

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) == 0) {
        fprintf(stderr, "%s file offset [length]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    if (fstat(fd, &sb) == -1) {         /* To obtain file size */
        perror("fstat");
        exit(EXIT_FAILURE);
    }

    offset = atoi(argv[2]);
    pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
        /* offset for mmap() must be page aligned */

    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;
                /* Can't display bytes past end of file */

    } else {    /* No length arg ==> display to end of file */
        length = sb.st_size - offset;
    }

    addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
                MAP_PRIVATE, fd, pa_offset);
    if (addr == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
    if (s != length) {
        if (s == -1)
            perror("write");
        else
            fprintf(stderr, "partial write");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
} /* main */
 

関連項目

getpagesize(2), mincore(2), mlock(2), mmap2(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shm_open(3)
B.O. Gallmeister, POSIX.4, O'Reilly, pp. 128-129 and 389-391.


 

Index

名前
書式
説明
返り値
エラー
準拠
可用性
注意
バグ
関連項目

This document was created by man2html, using the manual pages.
Time: 04:31:53 GMT, November 19, 2007