mremap -
仮想メモリーアドレスを再マッピングする
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <sys/mman.h>
void *mremap(void *old_address, size_t old_size,
size_t new_size, int flags, ... /* void *new_address */);
mremap()
は既存のメモリーマッピングの拡張
(または縮小) を行う。
同時に移動されることもある
(
flags
引き数と利用可能な仮想アドレス空間によって決まる)。
old_address は拡張
(または縮小)
しようとする仮想メモリーブロック
の元のアドレスである。
old_address
はページ境界に合っていなければ
ならない点に注意すること。
old_size
は元の仮想メモリーブロックの
サイズである。
new_size
は要求する変更後の仮想メモリーブロックのサイズである。
5 番目の引き数として
new_address
を指定することができる。下記の
MREMAP_FIXED
の説明を参照のこと。
Linux
ではメモリーはページに分割される。ユーザープロセスは
(一つまたは)
複数のリニアな仮想メモリーセグメントを持つ。
それぞれの仮想メモリーセグメントは一つ以上の実メモリーページ
にマッピングされている
(マッピング情報はページテーブルで管理される)。
仮想メモリーセグメントにはセグメント毎の保護
(アクセス権)
が設定されており、
メモリーが不正にアクセスされた場合
(例えば読み込み専用のセグメントに
書き込んだ場合)、セグメンテーション侵害
(segmentation violation) を
引き起こす。また、セグメント外の仮想メモリーにアクセスした場合にも
セグメンテーション侵害が発生する。
mremap() は Linux
のページテーブル方式を使用する。
mremap()
は仮想アドレスとメモリーページのマッピングを変更する。これは非常に効率的な
realloc(3)
を実装するのに使用されている。
flags
ビットマスク引数は 0
または以下のフラグを含む:
- MREMAP_MAYMOVE
- デフォルトでは、現在の位置にマッピングを拡張するための
十分な空きがなければ
mremap() は失敗する。
このフラグが指定されると、カーネルは必要があればマッピングを
新しい仮想アドレスに再配置することができる
マッピングが再配置されると、古いマッピング位置への絶対ポインターは
無効になる
(マッピングの開始アドレスからの相対オフセットは有効のままである)。
-
MREMAP_FIXED (Linux 2.3.31 以降)
- このフラグは
mmap(2) の MAP_FIXED
フラグと似たような目的で用いられる。
このフラグが指定されると、
mremap() は 5
番目の引き数
void *new_address
を受け取り、この引数はマッピングが移動されるべきアドレスを指定する。
このアドレスはページ境界に合っていなければならない。
new_address と new_size
で指定されるアドレス範囲に過去のマッピングがあった場合、
そのマッピングはアンマップされる
(unmapped)。 MREMAP_FIXED
を指定した場合は、
MREMAP_MAYMOVE
も指定しなければならない。
old_address と
old_size
で指定されるメモリーセグメントが
(
mlock(2) や同様のもので)
ロックされている場合、セグメントのサイズが変わったり
再配置されたりした時にロックも維持される。
その結果、プロセスによってロックされるメモリーの量は変化する。
成功した場合は
mremap()
は新しい仮想メモリー領域へのポインターを返す。
エラーの場合は
MAP_FAILED
(すなわち
(void *) -1)
が返され、
errno
が適切に設定される。
- EAGAIN
- 呼び出し元がロックされているメモリーセグメントを拡張しようとしたが、
RLIMIT_MEMLOCK
リソース制限を越えずにこれを行うことができない。
- EFAULT
- 「セグメンテーション違反(segmentation
fault)」 old_address から
old_address+old_size の
範囲のアドレスのどれかがこのプロセスにおいて不正な仮想メモリーアドレスである。
たとえ要求したアドレス空間全体を含むようなマッピングがあったとしても、
それらのマッピングが異なった型ならば
EFAULT
を受け取るだろう。
- EINVAL
- 不正な引き数が与えられた。
可能性のある原因は以下の通りである:
たいていは old_address
がページ境界に
合ってない; flags に
MREMAP_MAYMOVE または MREMAP_FIXED
以外の値が指定されている;
new_size がゼロ; new_size
または new_address
の値が不正; new_address と
new_size
で指定される新しいアドレス範囲が
old_address と old_size
で指定される古いアドレス範囲と重なっている;
MREMAP_FIXED
が指定されているが
MREMAP_MAYMOVE
が指定されていない。
- ENOMEM
- 現在の仮想アドレスではメモリー領域が拡張できず、
MREMAP_MAYMOVE フラグが flags
に設定されていない。
または十分な (仮想)
メモリーが存在しない。
このコールは Linux
特有であり、移植を意図したプログラムで
使用すべきではない。
バージョン 2.4 より前の
glibc では、
MREMAP_FIXED
の定義は公開されておらず、
mremap()
のプロトタイプは
new_address
引き数を取らなかった。
brk(2),
getpagesize(2),
getrlimit(2),
mlock(2),
mmap(2),
sbrk(2),
realloc(3),
malloc(3)
ページ分割されたメモリーについてもっと詳しく知りたいならば、あなたのお気に入りのオペレーティングシステムの教科書を参照してほしい
(例えば、
Modern Operating Systems by Andrew S.
Tanenbaum,
Inside Linux by Randolf Bentson,
The Design of the UNIX
Operating System by Maurice J. Bach.)
この man ページは Linux
man-pages
プロジェクトのリリース
3.79 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。