デーモンとは、イベントを待ってスリープしているプロセスのことである。 イベントが発生すると、デーモンは目を覚まし、仕事をしてからまた眠るというわけである。 …じゃあプロセスっていったい何だろう。
プロセスとは、実行中のプログラムのことを指す用語だ。 プロセスは、プログラム本体、データ、スタック、プログラムポインタ、スタックポインタ、すべてのレジスタ、その他プログラムの実行を支えている様々な情報によって構成されている。 なんのことやらさっぱり分からんという場合も、まあ気にしないで先に進んでほしい。
最近の OS は、だいたいマルチプロセスをサポートしている。 つまり、複数のプログラムを同時に実行できるようになっている。 とはいえ、コンピュータには1つの CPU しか搭載されていない。 たった1つの CPU で、複数のプロセスを同時にサポートするにはどうするか。 そのための仕組みがタイムシェアリングである。
いまコンピュータの上で、5つのプログラムが同時に実行中であるとしよう。 それぞれはプロセスという概念で管理されている。 プロセス A が最初に実行され、たとえば 50ms (20分の1秒)が過ぎたとしよう。 OS は割り当てられた時間が切れたと判断して、いったんプロセス A を凍結する。 そして次のプロセス B を実行に移す。 さらに 50ms が過ぎると、今度はプロセス B が凍結され、プロセス C が実行される。 こうして順に D、E のプロセスが実行され、ふたたびプロセス A の順番が回ってくる。 凍結されていたプロセス A は、そっくりそのまま復元されて、中断したところから再開される。 そして、割り当てられた 50ms を実行すると、またまた凍結されて次のプロセスへ順序を譲るのである。 このような切り替えは、十分に高速に行えば、まるでそれぞれのプロセスが同時に動作しているように見えるというわけである。
プロセスというのは、このような切り替えを行う上での単位となる重要な概念である。 FreeBSD を含めて Unix によって動作しているコンピュータは、常時 20 個ほどのプロセスが実行されている (ps コマンドを使えば、プロセスのリストを見ることができる)。 インターネットサーバとして利用されているマシンならば、200個とか500個にもおよぶプロセスが、せわしなくクライアントからの要求を処理しているはずだ。
このようなプロセス同士は、原則として互いに相手に干渉できない仕組みになっている。 たとえば個々のプロセスには、専用のメモリ空間が割り当てられ、他のプロセスからメモリにアクセスされたり、勝手に書き換えられたりできないよう、きちんとした保護機能が用意されている。 しかし、一方では保護機能のない資源もある。
たとえば、プリンタを使ってファイルを印字しようとしている2つのプロセスがあるとしよう。 プロセス A がファイルをオープンし、最初の2、3行を印字したところで割り当てられた 50ms が過ぎてしまったとしよう。 次のプロセス B が、やはりファイルをオープンし、自分で印字したい内容をプリンタに送りつける。 その結果、A と B の出力が完全に混じってしまうのである。 これではまともに印刷を行うことができない。
このような事故を防ぐために、様々な機構やプログラミングテクニックが存在するのだが、そのひとつにスプーリングという手法がある。
まずプリンタから印刷を行いたいプログラムは、スプールと呼ばれるディレクトリに、印刷したいファイルをコピーするというルールを作る。
そして、スプールにファイルが置かれると、それを選んでプリンタに送り込み、印字を完了させる専用のプログラムを用意する。
印刷プログラムは、スプールにコピーされたファイルを順番に処理するので、印字結果が混ざってしまうような事故は起こらないという寸法である。
この、「ファイルがコピーされたら印刷する」というプログラムこそが、デーモンと呼ばれる種類のプロセスなのである。
デーモンには色々な種類がある。 ちょっと ps の出力例をお目にかけよう。
% ps ax PID TT STAT TIME COMMAND 0 ?? DLs 0:00.80 (swapper) 1 ?? Is 0:00.05 /sbin/init -- 2 ?? DL 0:01.74 (pagedaemon) 3 ?? DL 0:00.00 (vmdaemon) 4 ?? DL 6:25.20 (syncer) 36 ?? Is 0:00.00 adjkerntz -i 98 ?? Is 0:06.80 syslogd 103 ?? Is 0:16.54 named 108 ?? S<s 2:03.91 xntpd -p /var/run/xntpd.pid 112 ?? Is 0:00.07 portmap 124 ?? Is 0:00.15 mountd -r 127 ?? Is 0:00.00 nfsd: master (nfsd) 135 ?? Is 0:00.00 rpc.statd 140 ?? I 0:00.22 nfsiod -n 4 148 ?? Is 0:01.97 amd -p -a /net -c 1800 -k i386 -d srs.ne.jp -l syslog 172 ?? Is 0:00.31 inetd 175 ?? Is 0:11.37 cron 179 ?? Is 0:09.85 sendmail: accepting connections on port 25 (sendmail) 228 ?? Is 0:00.00 /usr/local/pgsql/bin/postmaster -D/usr/local/pgsql/da 241 ?? I 0:54.29 /usr/local/bin/Wnn6/jserver 34541 ?? Ss 0:14.69 /usr/local/apache-1.3.6p/bin/httpd 42136 ?? Ss 0:03.07 telnetd 42137 p0 Ss 0:00.16 -tcsh (tcsh) 42149 p0 T 0:23.13 mule -nw daemon.txt 42225 p0 R+ 0:00.00 ps -ax 261 v0 Is+ 0:00.01 /usr/libexec/getty Pc ttyv0 262 v1 Is+ 0:00.01 /usr/libexec/getty Pc ttyv1 263 v2 Is+ 0:00.01 /usr/libexec/getty Pc ttyv2 240 con- I 0:00.00 /usr/local/bin/Wnn6/jserver
冗長な部分は省略しているが、だいたいこんな感じである。 上から順に紹介していこう。
swapper ページスワップを処理するデーモン init 最初のプロセス。すべてのプロセスの親 pagedaemon ページングデーモン vmdaemon 仮想メモリを管理するデーモン syncer ディスクとキャッシュの同期を取るデーモン adjkerntz BIOS のローカルタイムとシステムクロックを同期させるデーモン syslogd エラーメッセージなどを記録するデーモン named DNS サーバ (name daemon) xntpd NTP を処理するデーモン portmap RPC サーバ mountd NFS マウントデーモン nfsd NFS サービスサーバ rpc.statd ホストステータス監視デーモン nfsiod NFS 非同期I/O サーバ amd オートマウントデーモン inetd インターネットスーパーサーバ cron コマンドスケジュールデーモン sendmail メールデーモン postmaster データベースサーバ jserver かな漢字変換サーバ (Wnn) httpd Web サーバ (Apache) telnetd telnet サーバ tcsh シェル mule エディタ ps このリストを表示しているプログラム getty ターミナルを初期化し login を受け付けるプロセス
このマシンは個人専用で使っているため、ユーザプロセスといえば原稿を書いている自分のエディタぐらいしかないという片寄った例になってしまったが、 ほとんどがデーモンであることは分かっていただけると思う。
というわけで、デーモンと Unix は切っても切れない深い関係にある。 災厄をもたらす悪魔というよりは、守護神といったところだろう。 たとえば FreeBSD のマスコットは、fork にちなんだ三つ又の槍を手に持つデーモンである。 スニーカーを履いているのは、たぶん大学で生まれたことの名残なんじゃないかと思う。