web-dev-qa-db-ja.com

孤立したプロセスグループでインタラクティブシェルは何をすべきですか?

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つの解決策がありますが、どちらも理想的ではありません。

  1. PidがグループIDと一致するプロセスにシグナルを送信してみてください。それがESRCHで失敗した場合、それはおそらく孤立していることを意味します。
  2. _/dev/tty_から1バイトのノンブロッキング読み取りを試してください。それがEIOで失敗した場合、それはおそらく孤立していることを意味します。

(これを追跡する問題は https://github.com/fish-Shell/fish-Shell/issues/422

あなたの考えをありがとう!

10
ridiculous_fish

私はあなたの分析に同意し、プロセスグループが孤立しているかどうかを検出する必要があるように思われることに同意します。

tcsetattr は、プロセスグループが孤立している場合(およびSIGTTをブロック/無視していない場合)にEIOを返すことも意味します。OU。これは、ターミナルのreadよりも邪魔にならない方法かもしれません。

次の方法で再現できることに注意してください。

(bash<&1 &)

リダイレクトが必要です。そうしないと、バックグラウンドでコマンドを実行するときにstdinが/ dev/nullにリダイレクトされます。

(bash<&1 & sleep 2)

ターミナルから2つのシェルが読み取られるため、さらに奇妙な動作が発生します。彼らはSIGTTINを無視しており、新しいプロセスが開始されると、フォアグラウンドプロセスグループに含まれなくなったため、新しいプロセスは検出されません。

ksh93の解決策はそれほど悪くはありません。あきらめる前に、そのループを(無限ではなく)最大20回だけ通過します。

4