kazmax - Linux で自宅サーバー

vfork - システムコールの説明 - Linux コマンド集 一覧表

  1. 名前
  2. 書式
  3. 規格の説明
  4. LINUX での説明
  5. 歴史的記述
  6. バグ
  7. 歴史
  8. 準拠
  9. 関連項目

名前

vfork - 子プロセスを生成し親プロセスを停止させる

書式

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

規格の説明

(SUSv2 / POSIX ドラフトより) vfork ()関数は fork ()と同じ働きをするが、 vfork ()で作成されたプロセスが vfork ()からの返り値を格納している pid_t 型の変数以外を変更したり、 vfork ()を呼び出している関数から return したり、 _exit ()や exec ()族の関数をコールする前に他の関数をコールした場合の動作が 未定義であるという点で異なっている。

LINUX での説明

vfork ()は   fork (2) と全く同じように呼び出したプロセスの子プロセスを生成する。 詳しい説明と返り値、エラーについては   fork (2) を参照すること。

vfork ()は   clone (2) の特殊な場合である。 親プロセスのページテーブルのコピーを行わずに新しいプロセスを 作成するために使用する。これは性能に敏感なアプリケーションにおいて 子プロセスを生成してすぐに execve ()する場合に有用かもしれない。

vfork ()は fork ()と違って子プロセスが   execve (2) または   _exit (2) をコールするまで親プロセスを停止(suspend)させる。 子プロセスは execve ()を実行するまではスタックを含めて全てのメモリを親プロセスと共有している。 子プロセスは現在の関数から return してはならない。また子プロセスは exit ()をコールしてはならいが、 _exit ()ならばコールしてもよい。

シグナル・ハンドラは継承されているが共有はされていない。 親プロセスへのシグナルは子プロセスが親プロセスのメモリを 解放した後に到着する。

歴史的記述

Linux において fork ()は書き込み時コピー(copy-on-write)ページを使用して実装されている。 そのため fork ()を使用することによって被る損害は親プロセスのページ・テーブルを 複製するために必要な時間とメモリだけである。 しかしながら忌しき昔には fork ()は呼び出したプロセスのデータ空間の全てのコピーしていたが、 これはしばしば不必要であった。なぜならば大抵はすぐに後に exec ()を実行していたからである。 この場合の効率を上げるために BSD は vfork ()システムコールを導入して親プロセスのアドレス空間を完全にコピー するかわりに、 execve ()をコールするか exit が起きるまで親プロセスのメモリと制御スレッド を借りるようにした。 親プロセスは子プロセスがその資源を使用している間は停止させられた。 vfork ()の使用はトリッキーであった: 例えば親プロセスの変数を変更しな いようにするためにはどの変数がレジスタに保持されているかを知らな ければならなかった。

バグ

Linux がこの過去の亡霊を復活させたことは、むしろ不幸と言うべきである。 BSD のマニュアルによると: 「このシステムコールは妥当なシステム共有機構が実装された場合には 削除される。ユーザは vfork ()のメモリ共有機能に依存するべきではない。何故ならば、このシステムコール が削除された場合には、それは fork ()の同義語とされるからである。」
厳密に言うと、上記の標準の記述では vfork ()を使用してはいけないことになる。なぜならば exec ()は失敗するかもしれず、その場合の動作は未定義だからである。
シグナル・ハンドリングの詳細は不明瞭でシステムごとに異っている。 BSD のマニュアルによると: 「デッドロック状態になる可能性があるので vfork ()の途中の子プロセスに SIGTTOU や SIGTTIN シグナルを送信してはならない; さらに出力や ioctl は許されるが、入力を試みた場合には結果はファイル終端(EOF)になる。」

現在のところ(Linux 2.3.25)、 strace (1)は vfork ()を追跡することができず、カーネルパッチが必要である。

歴史

vfork ()システムコールは 3.0BSD に現われた。 4.4BSD において fork ()の同義語となったが、NetBSD は再びそれを導入した。 http://www.netbsd.org/Documentation/kernel/vfork.html を参照。 Linux では 2.2.0-pre6 あたりまでは fork ()と等価であった。2.2.0-pre9 から(i386 では、他のアーキテクチャでは 少し遅れて)独立したシステムコールとなった。サポートは glibc-2.0.112 に追加された。

準拠

4.3BSD, POSIX.1-2001.
vfork ()コールは他のオペレーティング・システムの同名のコールと ちょっと似ているかもしれない。規格が vfork ()に要求していることは、 fork ()に要求していることよりは弱い。 それで両者を同じものとして実装しても適合になる。 特にプログラマーは execve ()または _exit ()を実行するまで親プロセスが停止していることや、メモリを共有するこ とによる特殊な動作をあてにすべきではない。

関連項目

  clone (2),   execve (2),   fork (2),  unshare (2),  wait (2)