setsid(2) のサポートが行なわれたときに記念に書いたものです。
現在は Ruby 1.9 系には
Process#daemon
があります。
これが標準で使えるようになるまでは daemon の作成に
Process#setsid
を使いましょう。
ruby-1.1b9_29 から setsid(2) がサポートされました(現在 1.8.6 がリリースされています)。
これで手軽に daemon プロセスがつくれます。
スクリプト言語ですが、手軽にちょっとしたサービスを実施できるようになるのはうれしいですね。
ここでの話は UNIX 系の OS が前提になりますが、POSIX の setsid をサポートしている場合には、同じことが可能かも。
また、考え方自身は C でプログラムをつくるときなどと共通です。 ただし、Ruby で実現するのはとても簡単なんですよ。
普段 Linux などを使用していると、自分が起動した覚えがないプロセスがいくつか動いていると思います。 その中の多くのものは daemon プロセスと呼ばれるものです。 サービスのために定期的に動くものや、サービスの要求を待っていて答えるものなどがあります。 有名なところでは、
httpd
syslogd
inetd
d」がついていますが、これは偶然ではなく daemon を意味しています。
HTTP をサポートする daemon なので httpd なのです。
つまり、daemon プロセスはあるサービスを実施するために、常に常駐しているプロセスのことを示します。
daemon プロセスは簡単につくれるでしょうか? Linux などでは、バックグラウンドでプロセスを起動するのにコマンドラインから次のよう指定します。
$ checkprogram &このように起動すると、プログラムは動きだし、必要なサービスを実施します。 ネットワークでサービスしたり、ファイルを監視したりするプログラムなどが作成できるはずです。 では、普通に作成したプログラムを、このように起動するのと、daemon プロセスは何が違うでしょう?
ps コマンドで、プロセスの状態をみてみます。
USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND root 111 0.0 0.5 956 424 ? S 07:07 0:00 syslogd root 153 0.0 0.4 936 368 ? S 07:07 0:00 inetd root 190 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 201 0.0 1.0 1388 796 ? S 07:07 0:00 httpd nobody 202 0.0 1.0 1388 816 ? S 07:07 0:00 httpd nobody 203 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 204 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 205 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 206 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 207 0.0 0.9 1364 716 ? S 07:07 0:00 httpd nobody 208 0.0 0.8 1364 712 ? S 07:07 0:00 httpd nobody 209 0.0 0.8 1364 704 ? S 07:07 0:00 httpd nobody 210 0.0 0.8 1364 704 ? S 07:07 0:00 httpd tetsu 3121 0.0 0.5 1032 444 p0 R 09:31 0:00 ps aux tetsu 3122 0.0 0.6 1272 508 p0 S 09:31 0:00 less
httpd などの daemon と ps や less などの一般のコマンドです。
どこか違いませんか?
少しややこしい話になりますが、deamon プロセスはプロセスがターミナルを持っていません。
ps の出力で TTY のエントリが「?」になっています。
これがプロセスが所属するターミナルがないということを意味しています。
ここでの「ターミナル(端末)」は、プロセスが所属する「制御端末」と呼ばれるものです。
このことが動いているプログラム(プロセス)にどう影響するのでしょう?
Linux などの UNIX 系の OS では、 一般にプロセスが、所属するターミナル(制御端末)を持っています。 起動されたターミナルが、プロセスグループを構成する単位になっています。 プロセスグループは、シグナルの影響する範囲に関係しています。
ログインすると、シェルが起動します。 そのログインシェルが属するターミナル(制御端末)が一つの単位(プロセスグループ)になっています。 そのため、ログインシェルから抜ける(ログアウトする)とき、起動していたプロセス(バックグラウンドプロセスを含め)にシグナルが送られます。 このようにして、ログアウトしたことをプロセスグループに伝える仕組みを持っています。
daemon プロセスは、このプロセスグループを独立したものを持つようにします。 そうしないと、他のプロセスのシグナルを不用意に受けてしまう可能性があるからです。
ちょっとややこしいんですが、「お決まり」なので... 詳しく勉強されたい方はすばらしくいい参考文献が 2 冊あります。 現在は絶版になっている可能性が高いのですが「W.Richard Stevens」さんが書かれた本は、どれもすばらしいのでみつけたら読んでみてください。
同じ著者の「UNIX ネットワークプログラミング 第二版 Vol.1 ネットワーク API: ソケットと XTI」。
制御ターミナルを持たないプロセスが、制御ターミナルに属していないターミナルをオープンすると、それが制御ターミナルになる。これを予防するために、fork(2) を二回実行するそうです。 現在は setsid(2)(注意のところを読んでみてください) を使った場合はどうか明示がないのですが。 私は「なせ二回 fork(2) するのか?」と思っていたので、これでようやく納得できたのでした。 こういう知識って、daemon プロセスを作成するときに大切ですけど、明示された情報源ってすくないですね。 daemon 作っています?
setsid をキーワードに Google すると、いろいろ情報がみつかります。 気になったら読んでみるといいと思います。
最初に setsid を使わない例です。
何もせずに 10 秒待っているだけのスクリプトです。
exit if fork sleep 10 exitこれを
ps コマンドで確認すると次のようになっています。
tetsu 3124 0.0 1.1 1756 948 p0 S 09:47 0:00 ruby daemon.rb
次に Process.setsid を使った例です。
daemon になっていますよ。
exit if fork Process.setsid sleep 10 exitこれを
ps コマンドで確認すると次のようになっています。
tetsu 3161 0.0 1.1 1656 920 ? S 09:56 0:00 ruby daemon.rb
ruby-1.1b9_29 だけは、次のパッチを行ってから使ってください。 ruby-1.1b9_30 以降は修正済です。
$ diff -u process.c.org process.c
--- process.c.org Fri Jul 3 16:06:35 1998
+++ process.c Sat Jul 4 10:03:18 1998
@@ -858,7 +858,7 @@
int pid = setsid();
if (pid < 0) rb_sys_fail(0);
- return NUM2INT(pid);
+ return INT2FIX(pid);
#else
rb_notimplement();
#endif