ちょっと、おバカなタイトルで攻めてみる。
親プロセス以外が、プロセスの終了を通知してもらう方法はあるのか?
という話。
最初に聞いたとき、脊髄反射的に、いろいろあるよーーー。と思った
do_exit()を追うだけでも、
profile_task_exit()
profile_handoff_task()
proc_exit_connector()
security_task_free()
このぐらい見つかる。
んが、どいつもこいつも、task_struct終了時通知なので、スレッドが死ぬ度に通知が飛びやがるのである。
しかもexit処理はいくつも同時に走りうるので、通知関数で
thread_group_empty()やら tsk->signal->live==1 やらでチェックするのもウマくない
(チェックしている最中にどんどん状態が変わるから)
さて、どうしたものか
P.S
ところで、netlinkのプロセスの生成・終了を監視する機構って全然ドキュメントないんだけど、誰が何のためにいれたんでしょ??
需要があるかどうか分からんけど、今度手引書書こうかしらん
追記
待てよ・・・
profile_handoff_task()
security_task_free()
の2つは put_task_struct()から呼ばれているのだからして、
thread_group_leaderは必ず最後にPF_DEADに遷移する。の規則により
この2つでif(pid==tgid) と判定するだけかぁ??
今度試す。
追記2
KAMEさんから、すごく素朴な指摘をうけて、ああ、説明が足りんかったと反省。
もっと具体的に書く。
あるプロセスにスレッドが2ついたとする、それぞれのpid, tgidは以下
そうすると、上記Hookはプロセス終了時に2回呼ばれる(スレッドが2つあるから)
ところが、たとえば、profile_task_exit() でprintkデバッグしていると以下の2つのケースがありうる。
ケース1)
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==1
ケース2)
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==2
ケース2で何が起こっているかというと
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==2
3.スレッドA atomic_dec(tsk->signal->live)
4.スレッドB atomic_dec(tsk->signal->live)
のように、do_exit()が2つのスレッドでほぼ同時に呼ばれる事により、
(このような状態はdo_group_exit()を呼ぶだけで簡単に作り出せる)
Hook関数からは、signal->liveの参照カウンタが2->2->0と変化したかのようにみえてしまっている。と。
んで、POSIX的にはmain thread に対してpthread_exit()を呼ぶことはアリなので、そうするとmain threadが最初にdo_exit()で抜けてくるやもしれず、pid==tgidでは判定できず、かつ、参照カウンタも信用できず。うーむ。
というのがそもそもの悩みだったのですよ。
監視プロセスが1つだけなら、ユーザーランドからkill -0 で定期監視すればいいけど、おいらが作っているのはミドルウェアで、監視対象が100とか10000とか増えてくると定期監視はいまいちヤル気がしないというのもあって、カーネルから通知してくれる口はないものかしら。と思っていた。と
そういうわです。
分かりにくくてすいませんm(_ _)m
親プロセス以外が、プロセスの終了を通知してもらう方法はあるのか?
という話。
最初に聞いたとき、脊髄反射的に、いろいろあるよーーー。と思った
do_exit()を追うだけでも、
profile_task_exit()
profile_handoff_task()
proc_exit_connector()
security_task_free()
このぐらい見つかる。
んが、どいつもこいつも、task_struct終了時通知なので、スレッドが死ぬ度に通知が飛びやがるのである。
しかもexit処理はいくつも同時に走りうるので、通知関数で
thread_group_empty()やら tsk->signal->live==1 やらでチェックするのもウマくない
(チェックしている最中にどんどん状態が変わるから)
さて、どうしたものか
P.S
ところで、netlinkのプロセスの生成・終了を監視する機構って全然ドキュメントないんだけど、誰が何のためにいれたんでしょ??
需要があるかどうか分からんけど、今度手引書書こうかしらん
追記
待てよ・・・
profile_handoff_task()
security_task_free()
の2つは put_task_struct()から呼ばれているのだからして、
thread_group_leaderは必ず最後にPF_DEADに遷移する。の規則により
この2つでif(pid==tgid) と判定するだけかぁ??
今度試す。
追記2
KAMEさんから、すごく素朴な指摘をうけて、ああ、説明が足りんかったと反省。
もっと具体的に書く。
あるプロセスにスレッドが2ついたとする、それぞれのpid, tgidは以下
pid tgid
--------------------------
スレッドA 101 101
スレッドB 102 101
そうすると、上記Hookはプロセス終了時に2回呼ばれる(スレッドが2つあるから)
ところが、たとえば、profile_task_exit() でprintkデバッグしていると以下の2つのケースがありうる。
ケース1)
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==1
ケース2)
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==2
ケース2で何が起こっているかというと
1.スレッドA profile_task_exit()
この時、tsk->signal->live==2
2.スレッドB profile_task_exit()
この時、tsk->signal->live==2
3.スレッドA atomic_dec(tsk->signal->live)
4.スレッドB atomic_dec(tsk->signal->live)
のように、do_exit()が2つのスレッドでほぼ同時に呼ばれる事により、
(このような状態はdo_group_exit()を呼ぶだけで簡単に作り出せる)
Hook関数からは、signal->liveの参照カウンタが2->2->0と変化したかのようにみえてしまっている。と。
んで、POSIX的にはmain thread に対してpthread_exit()を呼ぶことはアリなので、そうするとmain threadが最初にdo_exit()で抜けてくるやもしれず、pid==tgidでは判定できず、かつ、参照カウンタも信用できず。うーむ。
というのがそもそもの悩みだったのですよ。
監視プロセスが1つだけなら、ユーザーランドからkill -0 で定期監視すればいいけど、おいらが作っているのはミドルウェアで、監視対象が100とか10000とか増えてくると定期監視はいまいちヤル気がしないというのもあって、カーネルから通知してくれる口はないものかしら。と思っていた。と
そういうわです。
分かりにくくてすいませんm(_ _)m
コメント
コメント一覧 (12)
本文の状況説明が不親切すぎたので、追記2に状況を書き足してみました。
これで元々の悩みが分かっていただけるかしら?
if(t->signal->flags & SIGNAL_GROUP_EXIT)
が真となるときが、プロセス終了条件とみなしても無問題なんだけど、ここでは、もっと一般的な解はないの?
って事を考えています。
ミドルウェア作る立場からすると、ユーザがexitシステムコールを直接発行するだけで破綻するつくりはカッコよくないので。
無理してカーネルでやることない気もします。このあたりのタスク管理強化した拡張シェルのうまいデザインは分散コンピューティング系(統合)環境のインプリにあるはず。
工数と相談ですが。
アプリがfork-exec しないと仮定しているのは問題っす
というわけで、2.6.18系(あえてこう呼ぶ)では Documentation/accounting/taskstats.txt を使うのに一票。ちなみに 3000fork/s というログをみたことあるんで(運用中)注意。
明日、話を聞きにいくっす(^-^;;
たまたまこのページを見つけたものですが。
inotify 使えないかな?
/proc/{PID}
を監視対象に追加して、削除されるのを待つとか。
今使っているRHEL4だとinotifyないので、ちょっと遅くなるかもしれませんが、試してみて誤報告したいと思います m(_ _)m