mmap
mmap()
は、UNIXのシステムコールのひとつで、ファイルやデバイスなどのオペレーティングシステム (OS) 上のリソース(計算資源)の一部または全部を連続した仮想アドレス空間にマッピングする関数である。
ファイルシステム上のリソースに対するアクセス方法として、ストリームI/Oを行うシステムコールとの比較で、ユーザー空間とカーネル空間の間で読み書きされるデータのブロック転送が多くのアーキテクチャ上では発生しないことから、好まれる場合がある。
デバイスでは、ioctl()
とともにメモリマップドI/OやDMAなどの操作を抽象化するものとしてドライバからファイルI/Oサービスの一部として提供されることがある。
規格
[編集]mmap()
およびmunmap()
はPOSIXにより定義されており[1][2]、POSIX準拠のOSで利用することができる。POSIXで定められた動作のほかに、OSごとに独自の拡張が施されていることがよくあり、LinuxやFreeBSDでも、mmap()
はいくつかのOS固有のマッピングを生成可能である[3][4]。
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t len);
Microsoft Windowsの場合、Windows APIに相当機能が用意されている。ファイルマッピングに対応するものはCreateFileMapping()
[5][6]とMapViewOfFile()
[7]。無名マッピングに対応するものはVirtualAlloc()
[8]。
ファイルマッピングと無名マッピング
[編集]ファイルマッピング
[編集]ファイルを仮想アドレス空間へマッピングした場合、OSはファイル上の対象となる領域のデータを、ビューとして、mmap()
を呼び出したプロセスがアクセスできる仮想アドレス空間に割り当てる。そして、プロセスがマッピングされた領域へ書き込みを行った場合、MAP_SHARED
を指定した場合は、OSはその変更を同期的あるいは非同期的にファイルへと反映する。MAP_SHARED
と排他的なMAP_PRIVATE
を指定した場合は、変更はファイルには反映されない。
無名マッピング
[編集]ファイルの裏付けがないものを、無名 (anonymous) マッピングと呼ぶ。無名マッピングを使用するには第4引数flags
に MAP_ANONYMOUS
(またはMAP_ANON
)を指定し、ファイル記述子を表す第5引数に-1
を指定する。無名マッピングを使うと利用可能なメモリ領域を仮想アドレス空間から確保できる。この機能は、アプリケーションの実行中にOSから追加のメモリリソースを獲得する方法として利用される。多くのUNIX系の標準Cライブラリにおけるmalloc()
の実装は、小さなメモリ領域の確保はデータセグメントを拡張してそこから小分けに切り分け、大きなメモリ領域の確保のケースにはmmap()
を内部的に使っている。例えば、Doug Lea の実装した dlmalloc の場合、デフォルト値は256 KB以上のメモリ確保にmmap()
を使用する[9]。
複数プロセス間におけるmmap
[編集]複数のプロセスで、同じリソースの同じ領域をマッピングした場合の動作は、mmap()
呼び出し時のパラメータや、OSの提供するマッピングのセマンティクスによって異なる。また、MAP_SHARED
, MAP_PRIVATE
などのメモリの属性は、原則としてfork()
により生じた子プロセスにおいても保持されるが、これも変更することができる。
MAP_SHARED
[編集]MAP_SHARED
を指定すると、マッピングされたメモリ領域が複数のプロセスで共有される。あるプロセスがマッピングされた領域に書き込んだ内容を、他のプロセスが(同期的あるいは非同期的に)即座に読むことができるようになる。この性質は、プロセス間通信の手法の1つとして(UNIX System Vの共有メモリ機構の代替として)使われることがある。
MAP_PRIVATE
[編集]MAP_PRIVATE
を指定すると、マッピングがコピーオンライトになる。そこでは、マッピングされたメモリ領域からの読み取りしか行われていない状況が続く限りプロセス間でマッピングが共有されるが、あるプロセスがメモリ領域に何かを書き込もうとした瞬間にOSがマッピングを複製し、メモリ領域のコピーを生成したのち、その領域をプロセス固有のものとして位置づける。つまり、事実上、プロセス間ではマッピングが共有されていないということになり、この状況では、マッピングによるリソースへのアクセスは一貫性がないということになる。
子プロセスへは継承しないページ
[編集]fork()
は通常親プロセスの全てのメモリを子プロセスへ継承するが、mmap()
を用いてマップしたページについてはminherit()
を追加で呼び出すことにより、ページを子プロセスへ継承しない、ないしはゼロクリアすることができる。
具体的な応用例として暗号論的擬似乱数生成器(CSPRNG)がある。CSPRNGは乱数生成に必要な状態をメモリ上に保持する必要がある。fork()
を呼び出して子プロセスを生成すると、CSPRNGの状態もそのまま子プロセスへ継承してしまうため、両プロセスとも同じ乱数を生成してしまい、セキュリティ上の欠陥となる。これを防ぐため、CSPRNGの状態はmmap()
を用いて確保したメモリに保持し、さらにminherit(INHERIT_ZERO)
を呼び出して子プロセスではそのメモリをゼロクリアさせるようにする。これにより、子プロセスがCSPRNGを使用すると状態がゼロクリアされているため再度初期化を実行し、親プロセスとは異なる乱数を生成するようになる。
アドレス指定
[編集]通常は利用する仮想アドレス空間のアドレスは、mmap()
側が勝手に割り振るが、MAP_FIXED
を指定した場合、もし、そこが空き領域であれば、好きなアドレスを利用できる。ただし、アドレス 0 だけは使用できない。また、アドレスはページサイズ(多くのケースで4 KB)の倍数でないといけない。
関連項目
[編集]脚注
[編集]出典
[編集]- ^ mmap - map pages of memory | The Open Group Base Specifications Issue 7, 2018 edition / IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)
- ^ munmap - unmap pages of memory | The Open Group Base Specifications Issue 7, 2018 edition / IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)
- ^ mmap(2) - Linux manual page
- ^ mmap(2) | FreeBSD Manual Pages
- ^ CreateFileMappingA function (winbase.h) - Win32 apps | Microsoft Learn
- ^ CreateFileMappingW function (memoryapi.h) - Win32 apps | Microsoft Learn
- ^ MapViewOfFile function (memoryapi.h) - Win32 apps | Microsoft Learn
- ^ VirtualAlloc function (memoryapi.h) - Win32 apps | Microsoft Learn
- ^ dlmalloc
外部リンク
[編集]mmap
– The Open Group基本仕様書第7号2018年版「システムインターフェース」mmap(2)
– JM Project Linux System Calls マニュアル