New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
system() を呼んだ際に、終了した全ての子プロセスが回収されてしまう #187
Comments
_THREAD_SAFEが定義される時とされない時で同じ動作にしたいなら、そこのifdef消しちゃうのがいいんじゃないですか? どうやら_THREAD_SAFEはBSD系でだけで定義されるみたいですね。ここに関して言えば分ける意味はあまりなさそうです。 |
WNOHANG が渡されるかどうかが異なっています。 私も分ける必要は無いと思っていて、通常ここで WNOHANG を渡してループする必要なんて無いと思うんですが、コメントとして
とあったので、よくわからないですけど分けたままのほうがいいのかなと考えました。 |
そのコメント、つまりWNOHANGが要る、って言ってますよね。特にPython(のスレッド)絡みで問題になるからそっち使えと。 逆に @eagletmt さんのパッチでWNOHANG使って問題になることはありますかね? |
ポーリングになってしまうくらいで、大きな問題は無いと思います。 では ifdef を消したほうがいいですかね。 --- src/os_unix.c.orig 2012-04-03 00:57:55.810703746 +0900
+++ src/os_unix.c 2012-04-03 20:37:19.322730906 +0900
@@ -3734,7 +3734,6 @@
while (wait_pid != child)
{
-# ifdef _THREAD_SAFE
/* Ugly hack: when compiled with Python threads are probably
* used, in which case wait() sometimes hangs for no obvious
* reason. Use waitpid() instead and loop (like the GUI). */
@@ -3749,9 +3748,6 @@
mch_delay(10L, TRUE);
continue;
}
-# else
- wait_pid = wait(status);
-# endif
if (wait_pid <= 0
# ifdef ECHILD
&& errno == ECHILD |
修正内容としては筋が通ったものになったように思います。 仮にポーリングを嫌うなら、そもそもwhileループ自体が無効になるように直した方が好ましいですが、それは |
すみません。気づきませんでした……。ということは、バグということになったんですね。 |
バグじゃないです。 |
ふむふむ。了解しました。 |
一般的なプログラムとして、子供を1つしか持たない場合にその終了を待つのに 逆に |
孫以下がゾンビになったら、initの配下になるので大丈夫なはずです。 |
いやちがうw |
OH……。認識ミス。調べてみると、確かにそのとおりでした。
バグになったら、そこも修正するしかないですね。あとはこの変更により、その修正が必要になることが妥当かどうか、でしょうか。 |
Thanks. なるほど。Vim側で問題が出る(わずかな?)可能性は把握しました。 ところで次は子プロセス側なんだけど つまり元々の スクリプト の書き方が本質的に間違っているのでは?という問。まぁ、Vimが勝手に孫の終了補足しちゃうのは変な動作だけど、 |
そのスクリプトはもともとvimprocにあったもので、vimproc側で例外を補足している場合と補足していない場合があったのです。今は修正してあります。 |
つまり |
それはない。一度は取れる。Ⅰプロセスに対して1度waitされたかをカーネルが持ってる。 |
ちなみに同じプロセスIDに対して2度waitpidするとECHILDが出ます。 |
BSDのmanページより
ってところか。二重否定でわかりにくいけどw となるとコレを根拠に |
大分話がややこしくなっていますが、そもそも「vimprocで起動したプロセスがECHILDを発生させることがあるのでトラップしておいた」のが正解なのです。それを@eagletmtさんが原因を調べて、「Vimがwait()しているから」というのが明らかになりました。つまり、Vimがwait()をしなければ、vimproc(とvimprocを使ったプラグイン)にバグがない限り、ECHILDは発生しないはずなのです。 |
ちょっとGUIロックかけてるか見てみる。 |
かけてた。(一瞬だった) |
あ、嘘だ。 |
あー、すんません。wait()してるのメインループ側だったw |
あとは理由付けと、こう変える事でも弊害が無いんだよっていう説明がいる。 |
w 理由としては「waitpidに変えないと、if_*側で作ったプロセスに対するwaitpidが補足できないケースができちゃうよ」というあたりか。できれば「終了コードが取れなくなっちゃうYO!」とか言えるともっと良さそう。 弊害が無いことはここで検証したプロセスを書き下すだけかな。 |
この件、今は誰がボール握ってるんでしょう |
@eagletmt さんのパッチで私はOKだと思いますが、状況を伝えるのにちょっとだけ苦労するかも、くらい。 |
下手な英語で良ければ私がやります。要点だけ。
でok? |
OK |
mattn++; |
Patch 7.3.499 で入りました。イェイ! |
https://gist.github.com/2290573
この proc.vim を source して call Test() とすると、os.waitpid の時点で ECHILD により例外が投げられます。
これは Vim の system() の実装において、wait によって全ての子プロセスを待っていることが原因だと考えました。
実際、以下のように修正すると上記の例外は発生しなくなりました。修正後のコードはすぐ上の #ifdef _THREAD_SAFE の場合とほぼ同じです。
ゾンビを防いだり終了を待つ意味ではユーザ側で ECHILD を無視すればよいわけですが、終了ステータスを取得したい場合もあると思います。
The text was updated successfully, but these errors were encountered: