プロセスその3

図1は、VMSにおいてProcessが生成される手順をまとめたものだ。

図1:出典:VAX/VMS Internal and Data Structures Version 5.2(Fig 25.1)

馴染みの無い用語が並んでいるのですこし説明しよう。まず$SUMBIT Command Processed by CLIというのは、コマンドラインインタフェース(CLI)から$SUBMITをつかってバッチジョブを起動する、という話だ。UNIX系で言えば、

% foo.bar &

という具合に別プロセスで実行するのが、ユーザーから見ると一番近いが、意味合いから言えばatコマンドの方が正確かもしれない。SUBMITコマンドを発行すると、そこで指定したプログラムはJOBのキューリスト(Batch Queue)に追加され、システムがスケジューリング後に順次実行される形になるからだ。つまり、即時実行されるわけではなく、この点で&付き実行というよりもatに近い。ただatとも異なるのは、いつ実行するかの指定をユーザーではなくシステムが決める点だ。Batch Queueというのはシステム全体で管理され、例えば一度にいくつまでJobを同時に実行するか、とか、何時どうやってバッチジョブを走らせるか(例えば夜間はフルに走らせるが、昼間は走らせないorプライオリティを落す)などの制御はシステムレベルで決められる。このあたりの概念はUNIX系OSの持ち合わせていない(もっと正確に言えば、意図的に落としたというべきか。UNIXを生み出す契機となったMulticsにはJobに関してもう少しサポートがあった)。さて、これとは別にCard Reader / Terminal DriverからもJobを生成することが出来た。Card ReaderというのはPCのCardではなく、紙のカード、つまりパンチカードである。なんでこんなものが? と思われようが、VAXのユーザーはメインフレームから移行するというケースが多かったし、そうした環境ではパンチカードでJobの投入を行うなんてケースもあったからだ(*1)。

一方Terminal Driverというのは要するに画面の入力である。具体的に言えばログイン画面である。ログインする、という行為は新しいプロセスを生成するという事で、このためにはそのプロセスを管理するJobを生成する必要がある。これはCard Reader経由も同じで、パンチカードで何かしらの作業をさせる場合、その作業を担うプロセスを作る必要があり、そのためにはまずJobを生成する必要がある。

こうしてJob生成のニーズが出た場合、そうしたリクエストはJob Control Mailboxに一端格納される。Mailboxは(以前もちょっと出たが)、割り込み機能付きキューだと思えばよい。UNIXのMailboxとbiffが一体になったもの、というあたりだろうか?(*2)

このJob Control MailboxでJob Creationの要求はシリアライズされた上で、Job Controllerに引き渡される。ここでJob Controllerは新しいJobを生成した上で、$CREPRCサービスを呼び出し、新規Processを生成する。

ただ$CREPRCを呼び出すのはこれだけではない。Application内部で新規プロセスを作る(UNIXで言えばfork()/exec()にあたる)場合とか、DCL(Digital Command Language:要するにUNIXのShellである)で新規プロセスを作る($SPAWNが、先に出た"% foo.bar &"に一番近い。"$ SPAWN/NOWAIT foobar.exe"を実行すると、別プロセスでfoo.barが即時実行される)、あるいは$RUN/DEFコマンドを使い、別環境でプログラムを実行するような場合にも$CREPRCが呼び出される。なぜこの2つはJob Controllerを経由しないかというと、これらの場合に生成されるProcessは、親プロセスのJob情報を継承するからだ。つまり、生成されたProcessは、親Processと同じJobに所属することになる訳だ。このあたりをまとめたのが図2である。Processの生成には2種類ある、という事がお分かりいただけよう。

図2

$CREPRCは内部でPCB(Process Control Block) / JIB(Job Information Block) / PQB(Process Quota Block)の作成が行われる。もっともJIBが作成されるのは、まだJobが無い/新規Jobを生成する場合に限られ、それ以外の場合JIBは既存のものをそのまま利用する。PCBは文字通りProcessの管理を行うためのもので、JIBへのポインタ他、Process管理に必要なデータエリアを作成するものだ。最後のPQBだが、これは各プロセスが利用できるリソースを管理するためのものだ。その最大のものはメモリであるが、単に仮想記憶の割り当てエリアのみならず標準入出力の先とか仮想記憶の対象外であるNon-Paged Poolと呼ばれるメモリ領域など、様々なものを管理する。

余談になるが$CREPRCは言ってみれば単に管理領域を作成するだけで、そこに実際にメモリ領域を割り当てるのはSWAPPERの仕事になる。そして割り当てられたメモリ領域にプログラムをロードし、実行を開始するのはEXE$PROCSTRTの仕事という訳だ(続く)。

(*1)もっとも筆者は見た事がない。
(*2)勿論実装は全然違う。UNIXのBiffの場合、定期的にMailboxをチェックして、そこに新着メールがあればNotifyを上げる。VMSのMailboxの場合、そのものが新しいメッセージを受け取るとMailboxそのものがNotifyを上げる。
追記:脚注2を上の様に書いたところ、読者の方より、「本物のbiffは、mboxファイルにメイルを書き込むプロセス(sendmailの場合、mail.local)が、localhostのbiffポートへTCPで接続し、メイルを受け取ったユーザ名とmboxファイル内でメイルが書かれたoffsetを送ることで実現されています。通常は上記の接続をinetdが受付け、comsatを起動します。comsatはそのユーザがログインしているかを確認し、ログインしている場合はターミナルにメッセージを出します。」というご指摘を頂きました。調べてみると確かにその通りでした(こちらのソースで確認しました)。もっともcomsat.cを見てみると、結局内部でfor(;;)で無限ループを廻し、その中でハンドリングをしている(biffそのものは、単にcomsatに対してNofityを出すか出さないか、の指定をするだけのプログラムですね)形になります。なので、「UNIXのBiffの場合、定期的にMailboxをチェックして、そこに新着メールがあればNotifyを上げる。」という表現は間違っていましたが、VMSのMailboxの様に、そのものがNotifyをあげるわけでは無いという事は変わりません。以上お詫びして訂正いたします。