( https://stackoverflow.com/questions/13718394/what-should-interactive-shells-do-in-alone-process-groups の提案に従ってUNIXに再投稿する
簡単な質問は、シェルがttyを所有していない孤立したプロセスグループにある場合、シェルは何をすべきかということです。しかし、面白いので長い質問を読むことをお勧めします。
これは、お気に入りのシェルを使用して、ラップトップをポータブルスペースヒーターに変える楽しくてエキサイティングな方法です(あなたがそれらのtcsh変人の1人でない限り):
_#include <unistd.h>
int main(void) {
if (fork() == 0) {
execl("/bin/bash", "/bin/bash", NULL);
}
return 0;
}
_
これにより、bashはCPUを100%でペグします。 zshとfishは同じことをしますが、kshとtcshはジョブ制御について何かをつぶやいてからキールオーバーします。これは少し優れていますが、それほど多くはありません。ああ、それはプラットフォームにとらわれない犯罪者です。OSXとLinuxの両方が影響を受けます。
私の(間違っている可能性のある)説明は次のとおりです。子シェルは、フォアグラウンドにないことを検出します:tcgetpgrp(0) != getpgrp()
。したがって、それ自体を停止しようとします:killpg(getpgrp(), SIGTTIN)
。しかし、その親(Cプログラム)がリーダーであり、死亡したため、そのプロセスグループは孤立し、孤立したプロセスグループに送信されたSIGTTIN
はドロップされます(そうでない場合、何も再開できません)。したがって、子シェルは停止しませんが、バックグラウンドにあるため、すぐにすべてをやり直します。すすぎ、繰り返します。
私の質問は、コマンドラインシェルがこのシナリオをどのように検出できるか、そしてそれが行うための正しいことは何ですか?私には2つの解決策がありますが、どちらも理想的ではありません。
ESRCH
で失敗した場合、それはおそらく孤立していることを意味します。/dev/tty
_から1バイトのノンブロッキング読み取りを試してください。それがEIO
で失敗した場合、それはおそらく孤立していることを意味します。(これを追跡する問題は https://github.com/fish-Shell/fish-Shell/issues/422 )
あなたの考えをありがとう!
私はあなたの分析に同意し、プロセスグループが孤立しているかどうかを検出する必要があるように思われることに同意します。
tcsetattr
は、プロセスグループが孤立している場合(およびSIGTTをブロック/無視していない場合)にEIO
を返すことも意味します。OU。これは、ターミナルのread
よりも邪魔にならない方法かもしれません。
次の方法で再現できることに注意してください。
(bash<&1 &)
リダイレクトが必要です。そうしないと、バックグラウンドでコマンドを実行するときにstdinが/ dev/nullにリダイレクトされます。
(bash<&1 & sleep 2)
ターミナルから2つのシェルが読み取られるため、さらに奇妙な動作が発生します。彼らはSIGTTIN
を無視しており、新しいプロセスが開始されると、フォアグラウンドプロセスグループに含まれなくなったため、新しいプロセスは検出されません。
ksh93
の解決策はそれほど悪くはありません。あきらめる前に、そのループを(無限ではなく)最大20回だけ通過します。