bash-builtinがCPUを100%焼くのを待つ


15

少なくともGNU bashバージョン4.3.42 x86_64 && GNU bashバージョン4.3.11 x86_64で発生します

シグナルによって割り込み可能にするために(SIGUSR1として)sleep & wait $!単純な代わりに使用します。ただし、次のコマンドを実行すると、bashビルトインが奇妙な動作をするようです。sleepsleepwait

ターミナル1:

cat <(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
   )&

ターミナル2:

kill -10 /the pid of the subshell, printed by the previous command/

ターミナル1:

^C (ctrl + C)

次に、CPUを100%燃焼させるサブシェルを取得します。

ターミナル1:

pkill -P $(pgrep -P $$)

この現象が発生する理由について何かご存知ですか?

cat <(/subshell/)がバックグラウンドにない場合、問題は発生しません。


この動作を体験する別の方法

ターミナル1:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)&

ターミナル2:

kill -10 /the pid of the subshell, printed by the previous command/

ターミナル1:

fg
^C (ctrl + C)

次に、冷凍シェルを入手します。


この動作を体験する3番目の方法

ターミナル1:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)

ターミナル2:

kill -10 /the pid of the subshell, printed by the previous command/

ターミナル1:

^C (ctrl + C)

次に、冷凍シェルを入手します。


これをデバッグするには、おそらくソースからBashを構築し、どこでループしているのか(デバッガーでブレークするか、printステートメントを追加する)とループする理由を見つける必要があります。
カズ

1
奇妙な?ここではこれを再現できません。bash4.3.42(1)-release(x86_64-pc-linux-gnu)を使用しています。Debian 8.カーネル4.6.1-1。私はあなたが言うすべてのテストを行いますが、CPUはまだ正常に動作しています...私はあなたが言うように、fg、そしてCTRL + Cを含めて正確にやっています。
ルチアーノアンドレスマティーニ

bash4.4でビルトインとシグナルに関連するいくつかの変更が行われたことを読んだことを覚えていますが、ここで影響を受ける可能性があります。
phk 16

Bash 4.4.20はwait、これと非常によく似たスピンループの問題を修正します。サブプロセスを永久に生成するループでそれに見舞われました。ただし、4.4.20でシナリオをテストしましたが、それでも問題がありました。興味深いことに、私がビルドしたバージョンにデバッガーをアタッチすると、ループが発生していることがわかりましたが、ブレークアウトする効果あり、ループは再び「テスト」を出力し始めました。言い換えると、デバッガをアタッチすると、スピンループが停止しました。
ハーフガー

回答:


1

観察

  • ctrl+cSIGINTターミナル1のfgプロセスに送信します
  • したがって、実行kill -2 <PID>ターミナル2には打撃と同じであるctrl+cターミナルに1
  • ターミナル2で実行する前に上記の2つのポイントのいずれかを実行するとkill -10 <PID>、ハンドルがSIGINT正しく処理されます。
  • ターミナル2(信号の送信)で実行した後にそれ行うと正しく処理されず、問題のある動作につながりますkill -10 <PID>SIGUSR1SIGINT
  • kill -2 <PID>ターミナル2(SIGINT)をkill -15 <PID>SIGTERM)またはkill -9 <PID>SIGKILL)に交換すると、常に正しい信号処理が行われます。
  • kill -10 <PID>ターミナル2で実行すると、ビルトインwaitが中断されますtestが、信号SIGUSR1がトラップされてループが継続した後すぐにprintetになるため、ループは終了しません。
  • 送信SIGINTすると、実行中のループから抜け出してシェルがフリーズするか、割り込みwaitが発生せず、待機/凍結のままになります。

結論

SIGINT取得されず、正しく処理されSIGUSR1ないか、手動でトラップした後、または他のユーザー定義のトラップ後に無視されます。これは、プロセスがまだ存在していることを意味し、CPUを消費/加熱するか、シェルをフリーズする理由です。ターミナル2の実行kill -15 <PID>またはkill -9 <PID>プロセスの終了/強制終了により、ターミナル1の制御が戻り、CPUが緩和されます。

なぜこの問題が発生するのかは謎のままですが、カーテンの後ろで実際に何が起こっているのかを誰かが正確に説明できることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.