なるほどUnixプロセス読んだ - デーモン化のためのdouble fork

なるほどUnixプロセス ― Rubyで学ぶUnixの基礎を読みました。UNIXプロセスの話、特に実用的なforkの利用方法についての話がコンパクトにまとまっていてわかりやすかったです。あまり詳細に踏みこんでいるという感じではないけど、とっかかりにこの本にあるような知識があるのは良いと思いました。(シェルスクリプトから"foreman start"したときにCtrl-Cで終了できない現象の解説 - はこべブログ ♨ではまる前に読んでおいたら、もっとはやく問題解決できたと思います。)

第18章 デーモンプロセスに関係して二回目のforkについていろいろ調べたので、せっかくなのでメモを残しておきます。*1

第18章 デーモンプロセス では、プロセスをデーモン化するために必要な手順が丁寧に説明されています。その中で、プロセスを制御端末から切り離す手順として以下のようなコードが紹介されていました。

# プロセスグループリーダーでない子プロセスを生成(親プロセスは死ぬ)
exit if fork
# 子プロセスが制御端末のない新セッションに属するようにする
Process.setsid
# セッションリーダーではない孫プロセスを生成(子プロセスは死ぬ)
exit if fork
# ... 残りのデーモン化手順へ

特に最後のforkについては、このプロセスに制御端末が設定されないことをより確実にするために行うと説明されています。(制御端末の設定はセッションリーダーに対してしか行えないため)

なるほどなーという感じなのですが、逆に最後のforkを行わなかった場合(以下のコード)に、どのようにしたら制御端末を設定することができるのでしょうか。

exit if fork
Process.setsid
# !! さらに fork はしない !!

このプログラムに続けて制御端末を設定するコードを書くことはできるようで、不完全なデーモンプロセスに制御端末を割り当てる方法を教えてく… - 人力検索はてなで解説されています。Rubyの場合は端末デバイスをopenしてioctlでTIOCSCTTYコマンドを実行すると良いようです。

ioctlで実行できるTIOCSCTTYはtty_ioctl(4)に解説があります。そこには、"The calling process must be a session leader and not have a controlling terminal already."とあって、セッションリーダーが自分自身にしか制御端末が設定できないようになっています。最後のforkを行わなければ、セッションリーダーが自分自身に制御端末を再度設定する余地が残っている、わけですね。

しかし、わざわざ制御端末を設定できないようにしたあとで、自分から制御端末を再度設定するようなことってあるのでしょうか。

同じような疑問を抱かれている人もいるみたいで、親プロセスは2度死ぬ - デーモン化に使うダブルforkの謎 - 睡眠不足?!に解説が載っていました。つまるところ、端末デバイスをopenすると自動的に制御端末が設定されてしまうような環境もあるので、誤って制御端末が設定されないように念のためforkしておこう、というような理由のようです。

いくらデーモン化のためにいろいろやっても、プログラムのうしろのほうで気が狂ってsetsidしなおして制御端末を開けば、プロセスに制御端末を設定することはできように思います。よく言われているデーモン化の手順は、すべて必要というわけではなく、よくあるミスをだいたい回避しながらデーモン化してくれる、ベストプラクティスの集まりという感じなのですかね。


なるほどUnixプロセス ― Rubyで学ぶUnixの基礎
Jesse Storimer, 島田浩二(翻訳), 角谷信太郎(翻訳)
達人出版会
発行日: 2013-04-25
対応フォーマット: EPUB, PDF, ZIP

詳解UNIXプログラミング

詳解UNIXプログラミング

  • 作者: W.リチャードスティーヴンス,W.Richard Stevens,大木敦雄
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/12
  • メディア: 単行本
  • 購入: 8人 クリック: 103回
  • この商品を含むブログ (41件) を見る

*1:この二回目のforkはかなりFAQな感じみたいですね