慌てないでください。

慌てないでください。

私はそれを使用していますUbuntu14.04理解できない動作が発生します。

  1. コマンドを実行しますyes(デフォルトのシェルでは:吹く)
  2. CtrlZ停止するには入力してください。yes
  3. ランニングjobs。出力:
    [1]+ Stopped yes
  4. kill -9 %1停止するまで走ってくださいyes。出力:
    [1]+ Stopped yes
  5. ランニングjobs。出力:
    [1]+ Stopped yes

これは、3.16.0-30-genericパラレル仮想マシンで実行されるUbuntuにあります。

kill -9私のコマンドが終了しないのはなぜですか?はい注文する?私の考えでは信号を殺す捕まったり無視することはできませんか?どうやって終了できますか?はい注文する?

答え1

プロセスを一時停止するためのシグナルがブロックされました。ターミナルから:

$ yes
...
y
y
^Zy

[1]+  Stopped                 yes

2番目のターミナルで:

$ killall yes

最初の端末で:

$ jobs
[1]+  Stopped                 yes

$ fg
yes
Terminated

しかし、SIGKILL止めることはできません。 2番目の端末で同じことを行うと、killall -9 yes端末からすぐに結果が得られますyes

[1]+  Killed                  yes

したがって、kill -9 %1プロセスをすぐに終了しないbash場合は、プロセスを破棄するまで信号が実際に送信されないか、fgカーネルでバグが見つかりました。

答え2

慌てないでください。

奇妙なことは起こりません。ここにカーネルのバグはありません。これは、Bourne Againシェルとマルチタスクオペレーティングシステムの完全に正常な動作です。

覚えておくべきこと自殺を扱う、または応答することもできますSIGKILL。ここで何が起こっているのかは、Bourne Againシェルが何かを処理しているということです。今後ただ自分を殺す過程が実際には自分を殺したと自らに言っただけです。

yes停止点で何が起こるかを検討し、SIGTSTPBourne killAgainシェルを使用してこのコマンドを実行しました。

  1. シェルがプロセスSIGKILLに転送されます。yes
  2. 平行に:
    1. プロセスyesが実行され、すぐに終了するようにスケジュールされます。
    2. Bourne Againシェルは引き続き別のプロンプトを発行します。

あなたが1つを見て、他の人が別のものを見るのは、実行する準備ができた2つのプロセス間の単純な競争によるものです。ここでは、勝者は完全にマシン間で、そして時間の経過とともに変化することに依存します。 CPUが仮想であるという事実と同様に、システムの負荷も影響します。

興味深い場合は、ステップ2の詳細は次のとおりです。

  1. Bourne Againシェルが続きます。
  2. kill内部的に組み込まれたコマンドの一部として、作業テーブルのエントリを次のように表示します。通知メッセージを印刷する必要があります。次の利用可能なポイントで。
  3. コマンドを完了しkillてプロンプトを印刷する前に、ジョブに関する通知メッセージを印刷する必要があるかどうかを再確認してください。
  4. プロセスyesは自分で終了する機会がなかったので、シェルに関する限り、操作はまだ中止されます。したがって、シェルはジョブの「中止」ジョブステータス行を印刷し、対応する通知保留フラグをリセットします。
  5. プロセスyesがスケジュールされ、それ自体で終了します。
  6. カーネルは、コマンドラインエディタを実行していたシェルに、プロセス自体が終了したことを通知します。シェルは状態変更を記録し、ジョブを保留中としてマークします。
  7. enterループプロンプト印刷をもう一度押すだけで、シェルが新しいジョブステータスを印刷する機会を得ることができます。

ポイントは次のとおりです。

  • プロセス自体が終了します。 SIGKILLこれは魔法ではありません。プロセスは、ページエラー、(ネストされていない)割り込み、およびシステムコールの終了時に発生するカーネルモードからアプリケーションモードに戻るときに保留中の信号を確認します。唯一の特別なことは、カーネルが即時かつSIGKILL無条件の自殺以外の対応操作を許可せず、アプリケーションモードに戻らないことです。重要なことは、プロセスをカーネルからアプリケーションモードに切り替える必要があることです。そして信号に応答して実行するようにスケジュールされています。
  • 仮想CPUはホストオペレーティングシステムのスレッドです。ホストが仮想 CPU 実行をスケジュールしたという保証はありません。ホストオペレーティングシステムも魔法ではありません。
  • ジョブの状態が変わると、通知メッセージは印刷されません(使用しない限りset -o notify)。シェルが実行サイクルの次のポイントに達すると、印刷され、保留中の通知があることを確認します。
  • 通知保留フラグは、シグナルハンドラkillによって1回、2回設定されます。SIGCHLDつまり人々が見ることができるという意味だ。二つyesプロセス自体が終了するように再スケジュールされる前にシェルが実行されると、メッセージが表示されます。 1つは「中止」メッセージ、もう1つは「終了済み」メッセージです。
  • 明らかに、この/bin/killプログラムはシェルの内部作業テーブルにアクセスできないため、そのような動作を見ることはできません/bin/kill。通知保留フラグはハンドラによって一度だけ設定されますSIGCHLD
  • 同じ理由で別のシェルで処理している場合、 killこの動作は表示されません。yes

答え3

あなたが観察しているのは、このbashバージョンのバグです。

kill -9 %1ジョブは実際にはすぐに終了します。を使用してこれを観察できますps。 bashプロセスを追跡してシステムコールが呼び出されるタイミングを確認し、サブkillプロセスを追跡して信号を受信して​​処理するタイミングを確認できます。もっと興味深いのは、この過程で何が起こるのかを直接見て見ることができるということです。

bash-4.3$ sleep 9999
^Z
[1]+  Stopped                 sleep 9999
bash-4.3$ kill -9 %1

[1]+  Stopped                 sleep 9999
bash-4.3$ jobs
[1]+  Stopped                 sleep 9999
bash-4.3$ jobs -l
[1]+  3083 Stopped                 sleep 9999
bash-4.3$ 

他の端末から:

% ps 3083
  PID TTY      STAT   TIME COMMAND
 3083 pts/4    Z      0:00 [sleep] <defunct>

子プロセスはゾンビ。それは死んだ。残りはプロセステーブルのエントリだけです(ただし、メモリ、コード、開いたファイルなどはありません)。その項目は、親が通知して通過するまで保持されます。waitシステムコールまたはその兄弟のいずれか

対話型シェルは、死んだ子プロセスを確認し、プロンプトを印刷する前にそれをキャプチャする必要があります(特に設定しない限り)。このバージョンのbashでは、次の場合にこれを行うことはできません。

bash-4.3$ jobs -l
[1]+  3083 Stopped                 sleep 9999
bash-4.3$ true
bash-4.3$ /bin/true
[1]+  Killed                  sleep 9999

コマンドがプロンプトを印刷した直後にbashが "Killed"を報告することを期待できますが、kill競合状態のためこれは保証されません。信号は非同期で転送されます。killカーネルがシグナルを転送するプロセスを決定するとすぐに、システムコールはシグナルが実際に転送されるのを待たずにすぐに返されます。 bashは子プロセスの状態を確認し、まだ死んでいないことを確認し(子プロセスの終了を報告していwait4ない)、プロセスがまだ停止していることを印刷する時間を持つことができ、実際に発生します。エラーは、次のプロンプトの前にシグナルが送信されたが(psプロセスが終了したことを見て)、bashがまだ呼び出されていないwait4ことです(私たちが見ることができるように、これはまだタスクが「中断された」と報告されているためですが、残っているため、実際に bash はwait4次に呼び出す必要がある場合にのみゾンビを取得し、他の外部コマンドを実行します。

エラーは断続的に発生し、bashを追跡するときにそれを再現することはできません(おそらくbashが迅速に反応する必要がある競合状態であるため)。 bash 検査の前にシグナルが転送されると、すべてが期待どおりに発生します。

答え4

システムに何か奇妙なことが起こっている可能性があります。私の-9レシピでは、以下があるかどうかにかかわらずうまくいきます。

> yes
...
^Z
[1]+  Stopped                 yes
> jobs
[1]+  Stopped                 yes
> kill %1
[1]+  Killed                  yes
> jobs
> 

pidを取得し、jobs -pそれを殺そうとしますroot

関連情報