Mac OS Xのカーネル Xnuのメモ書き

ページフォルト


Rev.36を表示中。最新版はこちら

作成中


表1 ページフォルトの発生要因とその動作
ページフォルト
発生要因
結果
不正な仮想アドレスへのアクセスユーザモードでページフォルトが発生していた場合は、該当スレッドを終了させる。カーネルモードでページフォルトが発生していた場合はシステム停止。
物理ページがまだ割り当てられていない仮想アドレス空間へのアクセス物理ページを割り当てて、PTEを設定する。
プロテクション不正ユーザモードでページフォルトが発生していた場合は、該当スレッドを終了させる。カーネルモードでページフォルトが発生していた場合はシステム停止。
プロテクション不正(ReadOnlyのページへの書込み)COW(Copy On Write)処理を行なう。ページをコピーして書込み可能にする。






vm_fault()
ページフォルトのハンドラ
例外ハンドラルーチンkernel_trap(),user_trap()から呼ばれる。
メモリの割り当て時にもページフォルトをシミュレートして物理ページを割り当てるために呼ばれる。

vm_fault()の概要
vm_map_lookup_locked()
仮想アドレスに対応するvm_objectを取得する。
不正なアドレスへのアクセスでvm_objectがない場合はKERN_INVALID_ADDRESS。
プロテクション不正の場合はKERN_PROTECTION_FAILURE。

/*
* ページフォルト処理の高速処理
* 処理できない場合は諦めて(以下のwhileをbreak)
* 通常のフォルト処理を行なう。
*/
while (TRUE) { <-- shadowオブジェクトをたどる為にループさせている
m = vm_page_lookup(cur_object, cur_offset);
ページを取得
if (m != VM_PAGE_NULL) {
if (m->busy) {
スレッドをブロック
goto done;
}
:
if ((fault_type & VM_PROT_WRITE) == 0) {
/* ページへのリードかページ上のコードを
実行しようとしてフォルトした */


/* kmem_alloc()でメモリを確保した場合は、
物理ページのマップをここで作成する。
(fault_type:VM_PROT_NONEでページフォルトをシミュレートするため)
*/


FastPmapEnter:

PMAP_ENTER()でPTE設定

PAGE_WAKEUP_DONE(m) ページ待ちのスレッドがいたらWakeup

return KERN_SUCCESS;
}

/* ページへの書込みでフォルトが発生した場合 */

Copy On Writeの処理
vm_page_grab()で新しいページを取得し
vm_page_copy()でページをコピーする。

goto FastPmapEnter; pmap設定へ
} else {
/* ページがない場合 */

/*
* kmem_alloc_pageable()
で仮想アドレス空間のみ割り当てて、
* 物理ページが存在しない場合はなどは
、ここでページが確保&
* 割り当てられる。

*/

if (cur_object->shadow == VM_OBJECT_NULL) {
ページの割り当て処理

vm_page_alloc() ページを取得してvm_objectにつなげる

if (!map->no_zero_fill) {
ページを0で初期化
}

goto FastPmapEnter;
}
/* shadowオブジェクトがある */
shadowをたどる
continue;
}
}


kr = vm_fault_page() 仮想アドレスに対応した物理ページを取得する

PMAP_ENTER()


vm_page_lookup(object, offset)
指定objectのoffsetに該当するページ(vm_page_t)を返す。


COW (Copy On Write)
fork()などでアドレス空間を複製した場合に仮想アドレス空間は複製するが、物理ページはコピーせずに共有する。代わりに、物理ページを ReadOnlyにしてどちらかのスレッドがそのページに書込みを行なった際にページフォルトが発生するようにしておく。実際にページを共有している何れ かのスレッドがページに書込みを行ないページフォルトが発生した時点で物理ページがコピーされて書込み可にされる。このように、実際にページに書込む段階 になって初めてページの複製することをCopy On Writeと呼ぶ。
このように物理ページの複製を遅延させることで、fork()後の大量のページコピー処理の発生を抑えることができる。また、Readしか行なわないページはそもそもページのコピーが発生しなくなる。

[関連ページ]
例外処理


最終更新 2006/06/08 09:44:17 - kztomita
(2006/06/01 23:00:40 作成)


最近更新したページ