fork/execモデルの起源

UNIXを勉強すると、forkとexecが分離されていることに疑問を持ち、パイプやリダイレクトを使ってシェルを作り、その合理性に感動するというのが、お決まりのパターンになっているが、なぜこんな実装が生まれてきたのだろう。

WindowsのネイティブAPIであるNtCreateProcessや、その祖先とも言える*1VMSのsys$creprcは、意味的にはforkとexecが一体化されている。まぁ、こっちの方がプロセス生成という意味では自然なアプローチに感じられるが、sys$creprcの山のような引数を見ると、これを使ってプログラムを書く気は萎えてくる。input、output、errorって標準入出力のバインディングを変えるためだろうか。そうだとすると、UNIXモデルの方がシンプルで理に適っている。

fork、execはUNIX V1のころから存在するのだが、「The Evolution of the Unix Time-sharing System」によると、それ以前のPDP-7版ではfork、exec、waitシステムコールは存在せず、これらはシェルの機能として実装されていた。exitは存在した。ちなみに、この時点でリダイレクトには対応していたが、パイプやバックグラウンドプロセスには対応していなかった。その後、fork、execはシェルの機能からシステムコールに格上げされる。必要な機能はすでに実装済みだったので、forkの実装はPDP-7アセンブリでたった27行だったそうだ。V6でもCで27行だ。

さて、肝心のforkとexecを分離するアイデアはどこから来たのだろう。UNIXの専売特許かと思いきや、「The Evolution of ...」には、バークレーのSDS 930タイムシェアリングシステムでは分離されていたし、その事実をKenがよく知っていたと書かれている。「SDS 940 Time-Sharing System Technical Manual」によると、シェルをexecutive、プロセスをforkと呼んでいた。forkはプロセスのような階層構造を持っていて、forkを生成する際、メモリを共有することができた。斜め読みでちゃんと理解してないけど、メモリのオーバレイ構造をどう管理するかという技術的要件から、このような仕組みになったと想像する。UNIXはオーバレイではなく、セグメンテーション+プロセス単位のスワッピングなので、構造はより単純だ。むしろ、オープンファイル表などのカーネル資源も引き継ぐ(正確には子プロセスはfork時点の内容をコピー)ことが重要だと思うが、SDS TSSはどうなっていたのだろうか。そもそもユーザ当たり3つしかファイルをオープンできなかったみたいだし、それはない気がするな。

エレガントなアイデアも一夜にして現れたわけじゃなくて、試行錯誤や先人の知恵の上に成り立っているんだな。

UNIX原典―AT&Tベル研のUNIX開発者自身によるUNIX公式解説書

UNIX原典―AT&Tベル研のUNIX開発者自身によるUNIX公式解説書

*1:Dave Cutlerが設計したという意味ぐらいだが。