書式
#include <sys/mman.h>
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
int mlockall(int flags);
int munlockall(void);
説明
mlock() と mlockall() はそれぞれ、呼び出し元プロセスの仮想アドレス空間の一部または全部を RAM 上にロックし、メモリがスワップエリアにページングされるのを防ぐ。 munlock() と munlockall() は逆の操作で、それぞれ呼び出し元プロセスの仮想アドレス空間の一部または全部を ロック解除する。つまり、指定された仮想アドレス範囲のページは カーネルメモリマネージャーから要求されればスワップアウトするようになる。 メモリのロックとロック解除はページ単位で行われる。mlock() と munlock()
mlock() は addr から始まる長さ len バイトのアドレス範囲のページをロックする。 呼び出しが成功した場合には、 指定されたアドレス範囲を含む全てのページは RAM に残り続けることが保証される。 これらのページは後でロック解除されるまで RAM に残り続けることが保証される。munlock() は、 addr から始まる長さ len バイトのアドレス範囲のページのロックを解除する。 この呼び出しを行った後は、カーネルが、指定されたメモリ範囲を含む 全てのページを外部のスワップ空間に移動できるようになる。
mlockall() と munlockall()
mlockall() は呼び出し元プロセスのアドレス空間にマップされている全てのページを ロックする。これにはコード、データ、スタックの 各セグメント、共有ライブラリ、カーネルのユーザー空間データ、 共有メモリ、メモリ・マップされたファイルが含まれる。 システム・コールが成功した場合には全てのマップされたページは RAM に 残ることを保証される。 これらのページは後でロック解除されるまで RAM に残り続けることが保証される。flags 引数は以下の内容の一つまたは複数のビット OR から構成される:
- MCL_CURRENT
- 現在、プロセスのアドレス空間にマップされている全てのページをロックする。
- MCL_FUTURE
- 将来、プロセスのアドレス空間にマップされる全てのページをロックする。 例えば、ヒープ (heap) やスタックの成長により新しく必要になったページだけで なく、新しくメモリマップされたファイルや共有メモリ領域もロックされる。
MCL_FUTURE が指定されていると、以後のシステムコール (例えば、 mmap(2), sbrk(2), malloc(3)) は、ロックするバイト数が許可された最大値 (下記参照) を超えた場合に 失敗する可能性がある。 同様に、スタックの成長も失敗する可能性がある。 その場合、カーネルはスタックの拡張を拒否し、 SIGSEGV をプロセスに送る。
munlockall() は、呼び出し元プロセスのアドレス空間にマッピングされている 全てのページをロック解除する。
返り値
成功した場合は、これらのシステムコールはゼロを返す。 エラーの場合は -1 が返され、 errno が適切に設定され、プロセスのアドレス空間におけるロックは変更されない。エラー
- ENOMEM
- (Linux 2.6.9 以降) 呼び出し元は非ゼロの ソフト資源制限 RLIMIT_MEMLOCK を持つが、制限が許可している以上のメモリをロックしようとした。 この制限は、プロセスが特権 (CAP_IPC_LOCK) を持っている場合は適用されない。
- ENOMEM
- (Linux 2.4 以前) 呼び出し元プロセスが RAM の半分以上をロックしようとした。
- EPERM
- 呼び出し側が特権を持っていないが、 要求された操作を実行するには特権 (CAP_IPC_LOCK) が必要である。
mlock() と munlock() 用として:
- EAGAIN
- 指定されたアドレス範囲の一部または全てをロックすることができなかった。
- EINVAL
- start+len の加算の結果が start よりも小さかった (例えば、加算でオーバーフローが発生したなど)。
- EINVAL
- (Linux ではこの意味で使われない) addr がページサイズの倍数ではない。
- ENOMEM
- 指定されたアドレス範囲がプロセスのアドレス空間にマップされたページと 一致しない。
mlockall() 用として:
- EINVAL
- 未知の flags が指定された。
munlockall() 用として:
- EPERM
- (Linux 2.6.8 以前) 呼び出し元が権限 (CAP_IPC_LOCK) を持っていない。
準拠
POSIX.1-2001, SVr4.可用性
mlock() と munlock() が使用可能な POSIX システムでは _POSIX_MEMLOCK_RANGE が <unistd.h> で定義されている。 また、ページあたりのバイト数は、 <limits.h> で定義される定数 PAGESIZE から (定義されている場合)、もしくは sysconf(_SC_PAGESIZE) を呼び出すことで決定できる。mlockall() と munlockall() が利用可能な POSIX システムでは、 _POSIX_MEMLOCK は <unistd.h> で 0 より大きい値に定義されている (sysconf(3) も参照のこと)。
注意
メモリのロックの用途としては主に二つある: リアルタイム アルゴリズムと高いセキュリティの必要なデータ処理である。リアルタイムの アプリケーションは決定的なタイミングやスケジューリングを必要とするが、 ページングは予期しないプログラムの実行遅延をもたらす主要な要因となる。 リアルタイムのアプリケーションはたいていは sched_setscheduler(2) でリアルタイムスケジューラに変更される。 暗号やセキュリティのソフトウェアはしばしばパスワードや秘密鍵のデータの ような重要なバイト列を扱う。ページングの結果、これらの秘密が スワップ用の固定媒体に転送されるかもしれない。そして、セキュリティ・ ソフトウェアが RAM 上の秘密を削除して終了したずっと後になっても、 このスワップされたデータには敵がアクセスできる可能性がある (しかし、ラップトップといくつかのデスクトップコンピュータの サスペンドモードはシステムの RAM の内容をメモリのロックに関わらず ディスクに保存することに注意)。リアルタイムプロセスが mlockall() を使ってページフォールトによる遅延を防ごうとする場合、 関数呼び出しによってページフォールトが発生しないように、 時間制限の厳しい部分 (time-critical section) に入る前に 十分な量のロックされたスタックを確保しておく必要がある。 これを実現するには、十分な大きさの自動変数 (の配列) を確保し、 これらのスタック用のページがメモリ上に確保されるようにこの配列に 書き込みを行う関数を用意し、これを呼び出せばよい。こうすることで、 十分な量のページがスタックにマッピングされ、RAM にロックされる。 ダミーの書き込みを行うことによって、 時間制限の厳しい部分 (critical section) 内では書き込み時コピーによる ページフォールトさえも発生しないことが保証される。
メモリロックは fork(2) で作成された子プロセスには継承されず、 execve(2) が呼ばれたり、プロセスが終了した場合は 自動的に削除される (ロック解除される)。 mlockall() の MCL_FUTURE 設定は fork(2) で作成された子プロセスには継承されず、 execve(2) の中でクリアされる。
あるアドレス範囲に対するメモリロックは、そのアドレス範囲が munmap(2) によってアンマップされた場合は削除される。
メモリのロックは累積しない。 すなわち複数回 mlock() や mlockall() を呼び出してロックされたページでも、 対応する範囲に対して munlock() を 1 回呼び出したり munlockall() を呼び出したりするだけでロック解除される。 複数の場所や複数のプロセスにマップされているページは、少なくとも一つの場所、 一つのプロセスでロックされている限りは RAM に残り続ける。
Linux での注意
Linux では、 mlock() と munlock() は自動的に addr を端数切り捨てにより一番近いページ境界へと丸める。 しかし POSIX.1-2001 は addr がページ境界に合っていることを要求する実装も許している。 そのため移植性を意図したアプリケーションではきちんと境界に合わせた方が良い。Linux 固有の /proc/PID/status ファイルの VmLck フィールドには、 mlock(), mlockall() および mmap(2) MAP_LOCKED を使って、 ID が PID のプロセスがロックしているメモリ量 (キロバイト単位) が 表示される。
制限と権限
Linux 2.6.8 以前では、メモリをロックするためには特権 (CAP_IPC_LOCK) が必要で、 ソフト資源制限 RLIMIT_MEMLOCK はプロセスがどれだけのメモリをロックできるかの制限を定義する。Linux 2.6.9 以降では、特権を持つプロセスがロックできるメモリ量は無制限となり、 代わりにソフト資源制限 RLIMIT_MEMLOCK は特権を持たないプロセスがロックできるメモリ量の制限を定義する。
バグ
2.4.17 までの 2.4 シリーズの Linux カーネルには、 mlockall() MCL_FUTURE フラグが fork(2) で継承されると言うバグがある。 これはカーネル 2.4.18 で修正された。カーネル 2.6.9 以降では、特権を持ったプロセスが mlockall(MCL_FUTURE) を呼び出した後で、特権をなくした場合 (例えば、 実効 UID を 0 以外の値に変更するなどにより、 CAP_IPC_LOCK ケーパビリティを失った場合)、リソース上限 RLIMIT_MEMLOCK に達すると、それ以降のメモリ割り当て (例えば mmap(2), brk(2)) は失敗する。
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。