Skip to content

Instantly share code, notes, and snippets.

@arumons
Created February 15, 2013 04:19
Show Gist options
  • Select an option

  • Save arumons/4958567 to your computer and use it in GitHub Desktop.

Select an option

Save arumons/4958567 to your computer and use it in GitHub Desktop.
chap18
・デーモンプロセスはバックグランドで走るプロセス(ターミナルのコントロール下にはない)
・例えばWebサーバーとかDBとか
・デーモンプロセスはOSのコアでもある
・いろんなプロセスがシステムをうごかすためにバックグランドで走っている
・GUIシステム上のWIndowサーバーとかプリンタサービスとかオーディオサービスとか
・だから常に不快な'ding'音を鳴らすことができる
The First Process
・そのようなプロセスの中で特に重要なデーモンプロセスがある
・以前の章ですべてのプロセスは親プロセスを持っているということを話した
・これは本当に全てのプロセスに対して真といえるのか?
・例えば一番最初のプロセスについてはどうだろう
・これは古典的な「誰が創造者を創造するのか」問題だ
・上記の答えは簡単である。
・カーネルが立ち上がった時にinitと呼ばれるプロセスが生成される
・このプロセスのppidは0であり、全てのプロセスの祖先となる。
・これは最初のプロセスであり、自身は親を持たない。このプロセスのpidは1である。
Creating Your FIrst Daemon Process
・デーモンプロセスを作るのはそんなに大変ではない。
・あらゆるプロセスはデーモンプロセスになることができる。
・ここでは例としてrackプロジェクトを見てみる。
・RackはWebサーバーを立ち上げるためのrackupコマンドを提供している
・Webサーバーは終了しないプロセスの例としてうってつけである。アプリケーションがアクティブである限り、接続をlistenするサーバーが必要になるだろう。
・rackupコマンドはサーバーをデーモン化するオプションを持っている。
・サンプルを見てみる
Diving into Rack
・色々やってるけど、elseブロックの中を最初に見てみる
・1.9だとProcess.daemonをやれば今のプロセスをデーモン化してくれる。
・Process.daemonのMRI版のソースと格闘すればifブロックでやってることと同じことをやってるのがわかる
・そいでは何をやってるのか細かく見ていく
Daemonizing a Process
exit if fork
・forkして親の方をexitしている(forkがnon nilを返すのは親だけなので)
・親なしプロセスに対してppidを見ると1を返す。これはカーネルが常に立ちあげているのを保証している唯一のプロセス
・このfork処理はデーモンプロセスを作るのに必須の処理。
 なぜならこのスクリプトを立ち上げたターミナルにコマンドが終了したことを通知し、ターミナルにコントロールをも戻すから。
Process.setsid
これは3つのことを行う
・新しいセッションのセッションリーダーになる
・新しいプロセスグループのグループリーダーになる
・ターミナルのコントロールから外れる
これらが何を意味するのか詳細をみてみる
Process Groups and Session Groups
・プロセスグループとセッショングループはジョブコントロールに関する全てである
・ジョブコントロールによってプロセスが端末によってコントロールされる方法を参照できる。
・プロセスグループについて見てみる
・プロセスはグループに属している。そしてそれらのグループは固有のIDを持っている。
・プロセスグループは関連したプロセスの集まりであり、基本的には親プロセスとその子プロセスである。
・Process.setpgrpを使うことで任意のプロセスをグループにまとめることができる。
Process.getpgrp
Process.pid
・getpgrpとpidを出すと同じ値になる。
・基本的にプロセスグループidはプロセスグループリーダーのプロセスIDと同じになる。
・プロセスグループリーダーはターミナルから作られたプロセスである。
・irbをターミナルから立ち上げるとそれは新しいプロセスグループのグループリーダーになる。
・そこから派生した子プロセスは同じプロセスグループの一員として作られる。
・プロセスとforkして作られたプロセスはpidは異なるがgetpgrpが同じ。
・親なしプロセスの内容を振り返ると子プロセスはカーネルによって特別扱いされることはなかった。
・親プロセスがexitしても子プロセスは処理を続ける。但しターミナルの制御下にある親プロセスがシグナルによってkillされると違った振る舞いになる。
・バックアップのような長時間実行されるシェルコマンドを立ち上げたRubyスクリプトをCtrl-Cでkillした場合、何が起こるのか?
・バックアップスクリプトは親なしではない。親がkillされたら処理は止まる。
・親から子へとシグナルを送るようなコードは書いていないのにどうしてそうなるのか?
・ターミナルはシグナルを受け取ると、それをフォアグラウンドプロセスグループにいるプロセスに送る。
・今回のケースだとRubyスクリプトとシェルコマンドは同じプロセスグループにいるため、同じシグナルによって両方共killされることになる。
・次はセッショングループ
・セッショングループはプロセスグループの集まり。
・git log | grep shipped | less
・これらのコマンドはそれぞれがプロセスグループに属してるため、Ctrc-Cで全てをkillすることができない
・これらのコマンドは同じセッショングループに所属している
・単一のコマンドやパイプによって連結されたコマンドは同じセッショングループに属する
・上記の例の用にセッショングループはターミナルに紐付くこともあれば、デーモン用にどのターミナルにも接続されない場合もある。
・プロセスグループと同様、ターミナルはセッショングループを特別な方法で処理する。セッションリーダーにシグナルを送ると
 セッションに属しているすべてのプロセスグループに同じシグナルを送る。
・getsidは現在のセッショングループIDを返が、Rubyのコアライブラリはインタフェースを提供していない。
・代わりにProcess.setsidを使うことで新しいセッショングループidが返される。
・Rackの例に戻ると最初にforkし、親を終了させている。
・ターミナルはexitを認識し、コントロールをユーザーに戻すが、フォークしたプロセスはまだ親から継承した
 グループIDとセッションIDを持ち続けている。
・この時点ではフォークしたプロセスはセッションリーダーでも、グループリーダーでもない。
・そのため、ターミナルはフォークしたプロセスへのリンクをまだ持ち続けている。
・もしセッショングループに対してシグナルを送ったら、それはフォークしたプロセスにも届く
・デーモンプロセスを完全にターミナルから切り離したい
・Process.setsidはフォークしたプロセスを新規のプロセスグループとセッショングループのリーダーにする
・既にプロセスグループのリーダーである場合、Process.setsidは失敗する。これは子プロセス対してのみ可能
・新しいセッショングループはターミナルのコントロールを持たない。しかし技術的にはアサインすることができる。
exit if fork
・フォークしたプロセスはプロセスグループとセッショングループのリーダーになる
・新しくフォークしたプロセスはプロセスグループやセッションのリーダーではない
・そのため以前のセッションリーダーはターミナルへのコントロールを持たず、このプロセスはセッションリーダーではない。
・そのためおkのプロセスが絶対にターミナルのコントロールを持たないことが保証される。
・ターミナルのみがセッションリーダーを割り当てることができる
・これらの処理はプロセスが完全に端末から切り離されていて、完了まで実行することを保証する
Dir.chadir "/"
は現在のワーキングディレクトリをrootにする
・これは厳密には必要な処理ではないが、ワーキングディレクトリが作業中に消されたり、アンマウントされたりすることが無いことを保証する
・/dev/nullへのreopenは標準入出力の宛先を全て/dev/nullを見るようにする。つまり全てが無視されるようにする
・デーモンはターミナルから切り離されているため、標準入出力は役に立たない
・標準入出力は他のプログラムから常に使われているため、クローズはできない
・/dev/nullへのリダイレクトを設定することで、標準入出力を有効にしつつ、何の影響も及ぼさないようにできる。
In the Real World
・言及したとおり、rackupコマンドはプロセスをデーモン化するオプションを用意している。
・大抵のRuby Webサーバーは同様の機能を備えている
・デーモンプロセスの詳細をさらに確認したいなら、「daemons」rubygemを見るといい。
・デーモンプロセスを自分で作ろうとするなら、自分にこう問いかけてみよう。「このプロセスは常にレスポンスを返せる状態にあるべきか?」
・もし答えがnoならデーモンではんかう、cronジョブやバックグランドジョブシステムを検討したほうが良い。
・もし答えがyesならデーモンプロセスは良い候補になる
System Calls
・RubyのProcess.setsidはsetsidにマップされている。
P・rocess.getpgrpはgetpgrpにマップされている
この章で言及したそれ以外のシステムコールは前の章で説明している
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment