Fork
Unixにとってforkは重要な機構概念であり、フィルタの開発を奨励している設計哲学の重要な部分を担っている。 Unixでのフィルタは標準入力を入力とし標準出力を出力とする(通常小さな)プログラムである。シェルがフィルタをパイプで連結することで、複雑な処理を実現できる。例えば次のようにfind(1)コマンドの出力をwc(1)コマンドの入力に連結すると、拡張子が ".cpp" のファイルをカレントディレクトリ配下で探し、見つかったファイル数を表示できる。
このコマンド行を入力すると、シェルは自分自身をforkし、プロセス間通信の1つであるパイプを使って find コマンドの出力を wc コマンドの入力に結びつける。パイプは2つの新たなファイル識別子を生成し、2つの子プロセスを生成する(それぞれ find と wc に対応)。2つの子プロセスはまず dup2(2) で対応するパイプのファイル識別子を複製して標準入力と標準出力に置き換える。そしてそれぞれの子プロセスがexec(3)ファミリのシステムコールを使って、実行すべきコマンドのプログラムで自身をオーバーレイする。
より一般的に、シェルはユーザーがコマンド行を入力するたびにforkを行っている。子プロセスはシェルがforkを行うことで生成され、子プロセスがexecでオーバーレイを行い、実行すべきプログラムのコードをマッピングする。
直後に exec または _exit() を呼び出す以外のvfork()の使用は推奨されない。特にLinuxのmanページではvforkそのものの使用が推奨されていない。
vfork()で生成した子プロセスがvfork()を呼び出したルーチンからさらに外側に復帰した場合、親プロセスのコールスタックを書き変えてしまうので、vfork()から親プロセスが戻ったときの動作を保証できない。また、execせずに子プロセスを終了する場合、_exit()ではなくexit()を使用すると、標準I/Oチャネルをフラッシュしてクローズするため親プロセスの標準I/O構造にダメージを与える危険性がある。なお、fork()の場合でも子プロセスがexit()を呼び出すのは危険である。
vfork()後に子プロセスでシグナルハンドラが呼び出された場合、子プロセスの他のコードと同じ規則に従う必要がある。
実行ファイルを実行しようとすると、プロセスが生成される。実行ファイルはセグメントと呼ばれるブロックにグループ化されたバイナリコードを含んでいる。各セグメントは特定の種類のデータを格納するのに使われる。典型的なELF形式の実行ファイルには、以下のようなセグメントが存在する。
text(英語版) — 実行可能なコードを格納したセグメント
.bss — 初期値がゼロのデータを格納したセグメント
data(英語版) — 初期値のあるデータを格納したセグメント
symtab — プログラムのシンボル群(例えば、関数名、変数名など)を格納したセグメント
interp — 使用すべきインタプリタの名前を格納したセグメント
readelf コマンドを使えば、ELF形式のファイルの詳細を表示できる。そのようなファイルを実行するためにメモリ上にロードすると、セグメント群がメモリにロードされることになる。実行ファイル全体を連続なメモリ位置にロードする必要はない。メモリはページと呼ばれる同じ大きさ(通常4KB)の部分に分けられている。したがって実行ファイルをメモリにロードする際、実行ファイル内のそれぞれの位置がそれぞれ異なるページに置かれる(ページ群は連続とは限らない)。大きさが10KBのELF形式の実行ファイルがあるとする。そのOSのサポートするページサイズが4KBなら、そのファイルは4KB、4KB、2KBという3つの部分に分けてロードされる(他にコールスタックも必要)。この3つのフレームはメモリ中の任意のフリーなページに置くことができる。