なぜ子プロセスを呼び出した時にsetsid()を使うのか?

tinytinyhttpd/httpd.cxx at master · mattn/tinytinyhttpd」のコードを読んでいた時に、以下のコードを見かけた。

    child = fork();
if (!child) {
setsid();
setpgid(0, 0);

setsid();とは、新たなセッションを作成する関数だが、なぜ子プロセスの実行前にsetsid()をしなければならないのかが分からなかった。

いろいろ調べてみても「これが100%正解だ」と言う結論には至らなかったが、いろいろな記事を調べた所、プロセスやセッションの理解が深まり、多分これと言う答えにたどり着いたので紹介していく。

そもそも、プロセスとかセッションって何?

そもそも、プロセスとかセッションとは何だろうか?基本的な所から、1つ1つ理解していこう。

プロセスとは、プログラムの実行単位のことで、機械語のコードとか変数を記憶するためのメモリが管理されている大きな箱みたいなもの。例えば、Excelを動かしたり、ssh接続したり、自作のプログラムを実行したりする時にプロセスが作成されて、そのプロセス内でプログラムが実行されている。

プロセスは1つ1つ独立したものだが、1つ以上の似たようなプロセスを集めて「プロセスグループ」と言う物も作られてる。名前の通り、ただのプロセスのグループなのだが、基本的には親プロセスとfork()で作成された子プロセスで構成されている。

そして親プロセスが、そのプロセスグループの「プロセスグループリーダー」を担っている。

そして、プロセスグループの集まりが「セッション」と呼ばれていて、そのセッションの親プロセスに当たるのが「セッショングループリーダー」と呼ばれている。

要はプロセスグループとかセッショングループは、プロセスを仲間分けしたもののような存在だと言える。

参考:プロセスグループ - Wikipedia

setsidは何をしてくれるのか?

では、setsid()は何をしてくれるかと言うと、Linuxの公式リファレンスでは以下のように書かれている。

setsid() は、 呼び出したプロセスがプロセスグループリーダー (process group leader) でなければ、 新しいセッションを作成する。 呼び出したプロセスは、 新しいセッションのリーダーとなる (すなわち、そのセッション ID がプロセス ID と同じ値になる)。 また、呼び出したプロセスは、 そのセッションの新しいプロセスグループのプロセスグループリーダーにもなる (すなわち、プロセスグループ ID がプロセス ID と同じ値になる)。

Man page of SETSID

つまり、setsid()がやっていることは、親プロセスと子プロセスの関係を引き離して、子プロセスを全く独立したセッション、プロセスグループのリーダーにしていることになる。

図解すると、以下の感じだろうか。

子プロセスを親プロセスから分離すると、何が嬉しいの?

setsid()の働きはわかったが、では、子プロセスを親プロセスから分ける事でどんなメリットがあるのか?

daemon - Why we use setsid() while daemonizing a process? - Unix & Linux Stack Exchange」では、以下のように述べている。

We use setsid() because if we just kill the parent the child will be killed too, the setsid()

上記の記事では「親プロセスが死んでも、子プロセスが生き続けるため」にsetsid()を実行すると書かれている。

これは僕の推測だが、子プロセスではrubyのコードを読んだりして、データベースなどの外部との処理を行っている場合もあり、その子プロセスを途中で終了するのは望ましくないからこそ、わざわざsetsid()を使うのでは、と思っている。(信頼できるソースがあれば良いが、今の所見つかっていない)

まとめ

いろいろ調べてある程度満足できるレベルでの理解はできたが、決定的な証拠が得られずに消化不良に終わってしまった。

ただ、元のソースコードでsetsid()を行っている理由がぼんやりと見えてきたので、今回はこれでよしとする。