Skip to main content.
Google custom search

NetBSD ドキュメンテーション: なぜ伝統的な vfork()を実装したのか


序 (トップ)

vfork() は、子プロセスがいずれ他のプログラムを exec()し、 かつ親プロセスはそれが起きるまで待っているという、特別な状況で 用いるために設計されたものです。 伝統的な fork() では、子プロセスに親プロセスの すべてのページを複製するという著しいオーバーヘッドが生じます。

COW (コピーオンライト)が追加された Mach VM システムでは fork() の負荷が大変軽くなり、 BSD 4.4では vfork()fork() と 同義のものとされました。 NetBSD 1.3 以降では、伝統的な vfork() が再実装されました。

UVMで COW を よりよいものにするために多大な努力がおこなわれました。 しかしアドレス空間を共有する vfork()いまだに 勝ることが分かったのです。 これにより、200MHz PPro での libcのビルドの所要時間を 数秒削ることができます。

4.4BSDの vfork()/exec() を使った vfork() と COW の処理 (トップ)

  • 親の vm_map をたどって、アドレス空間の書き込み可能な部分を COW とマークする。これは、 pmapを呼び出し、 PTEを修正し、 TLBをフラッシュすることを意味します。

  • 子プロセスの vm_map を生成し、親の vm_map エントリーを子の vm_mapにコピーします。 場合によっては、 pmapを呼び出して親のページテーブルから このページテーブルに PTE をコピーします。

  • 親をブロックします。

  • 子が走ります。 PTEがコピー されてない場合には、 ページフォルトが起きて現在プログラムカウンタのあるテキストページの物理マッピングが得られます。

  • 子は exec し、そして 作られたばかりのアドレス空間全体を unmapして 新しく作ります。 これは、親の vm_mapを辿って COWとマークされた部分を 非COWにする作業を伴います。

  • 親のブロックを解きます。

  • 親が走り、以前には R/W であって COWにするために R/Oとマークしたデータを 変更するとページフォルトを起こします。この時点ではデータのコピーは行なわれません。

アドレス空間共有を用いた 3.0BSD/NetBSD の vfork() の処理 (トップ)

  • 親プロセスの vmspace構造体への参照を得ます。

  • 親をブロックします。

  • 子が走ります。 親のページテーブルが用いられるので、 PTEは既に 有効でありページフォルトは起こりません。

  • 子が exec し、親の vmspace構造体に対して持っていた参照を削除し、 新しいものを作ります。

  • 親のブロックを解きます。

  • 親が走ります。(親の vm_mapは変更されていないので、 ページフォルトは起こりません。)

このように、fork してさらに execするような場合には、 明らかに後者がより高速です。 たとえ良い COWアルゴリズムを使っているとしても、仮想空間を共有する 場合と比べて大変多くの作業を行なわねばなりません!


Back to NetBSD ドキュメンテーション: カーネル