daemon起動時の二重forkの理由
カテゴリ: UNIX
daemonプロセスを起動する際に2回forkするというのは、もはやFAQの領域にあることだが、なぜ2回forkする必要があるのか、それぞれのforkにどういう効果があるのかということまで書いてあるものは少ない。私も今まで疑問に思いつつ放置していたが、ついにそのことについて書かれているものが見つかった。
Unix Programming Frequently Asked Questions 日本語訳 - 1 プロセス制御
1.7 プログラムをデーモンとして動かすにはどうすればいいですか?
これをきちんと理解するには、セッションと制御端末についてより詳しく知る必要がある。セッションとは、ユーザーがとある端末からログインして生成したプロセスの集合である。ユーザーは端末のキー操作によりプロセスの一時停止や終了などの制御を行うことができるが、セッションはこの制御の影響範囲を定義するものとなる。そしてその制御を行う端末が制御端末となる。各セッションはひとつの制御端末を持つが、制御端末を持たないセッションというのもありえる。そのようなセッション内のプロセスは、どのユーザーの制御下にも無いといえる。それこそがdaemonプロセスの要件であり、したがってdaemonプロセスの起動方法とは、制御端末を持たないセッションでプロセスを起動するという方法にほかならない。
ならば素直に制御端末を切り離せば良いと思うのだが、残念ながら移植性のある切り離し方法が無いのである。ioctrl()のTIOCNOTTYが使用できれば明示的に切り離しができるが、それが使えない場合、切り離す方法は存在しない。幸い、生成した直後のセッションは制御端末を持たないので、新たにセッションを作れば、制御端末を持たないセッションを作ることができる。
新たなセッションはsetsid()で作ることができるが、作るにはひとつだけ条件がある。setsid()を呼んだプロセスがプロセスグループリーダーであってはいけないということだ。プロセスグループとは、jobコントロールなどを行う為に、パイプライン等で繋げられた複数のプロセスをグループ化したものである。プロセスグループに含まれるプロセスのうち、一番最初に作られたプロセスがプロセスグループリーダーとなる。シェルから起動されたコマンドは、まず間違いなくプロセスグループリーダーになっている。これを回避する最も簡単かつ確実な方法は、プロセスグループにもうひとつプロセスを追加し、そこでsetsid()を呼ぶことである。これが1回目のforkの理由だ。ついでに自動的にバックグラウンドプロセスになるという効果もある。
制御端末無しのセッションはできたが、セッションを作ったプロセスつまりセッションリーダーはdaemonプロセスにとってはあまり嬉しくない性質を持っている。制御端末を持たないセッションのセッションリーダーが端末デバイスを開くと、それが制御端末になってしまうのだ。制御端末を捨て去る為に頑張ってきたのに、それがうっかり復活してしまうのは困ったことである。これを回避する最も簡単かつ確実な方法は、セッションリーダーのプロセスを捨てて、セッションリーダーではないプロセスで実行することである。ということで再度forkする。これでようやく制御端末を持たないセッションができあがるのだった。
コメントを投稿する