中断できないプロセスとは何ですか?
-
03-07-2019 - |
質問
Linuxでプログラムを作成し、ある種のバグが原因でクラッシュする場合は、いつでも中断できないプロセスになり、コンピューターを再起動するまで(ログアウトしても)永久に実行を続けます。私の質問は:
- プロセスを中断できない原因は何ですか?
- どうすればそれを防ぐことができますか?
- これはおそらく愚かな質問ですが、コンピューターを再起動せずに中断する方法はありますか?
解決
割り込み不可能なプロセスとは、システムコール(カーネル関数)内にあるプロセスであり、シグナルによって割り込むことはできません。
その意味を理解するには、割り込み可能なシステムコールの概念を理解する必要があります。典型的な例は read()
です。これは、ハードドライブのスピンアップやヘッドの移動を伴う可能性があるため、長時間(秒)を要する可能性があるシステムコールです。この時間のほとんどの間、プロセスはスリープ状態になり、ハードウェアでブロックされます。
プロセスがシステムコールでスリープしている間、UNIX非同期シグナル(たとえば、SIGTERM)を受信できます。その後、次のようになります。
- システムはexitを早期に呼び出し、ユーザー空間に-EINTRを返すように設定されています。
- シグナルハンドラが実行されます。
- プロセスがまだ実行中の場合、システムコールから戻り値を取得し、同じコールを再度行うことができます。
システムコールから早期に戻ることにより、ユーザー空間コードは信号に応じてその動作を即座に変更できます。たとえば、SIGINTまたはSIGTERMに反応して正常に終了します。
一方、一部のシステムコールはこの方法で中断することはできません。何らかの理由でシステムがストールを呼び出した場合、プロセスはこの強制終了できない状態のままになることがあります。
LWNは素敵な記事を実行し、7月にこのトピックに触れました。
元の質問に答えるには:
-
これを防ぐ方法:トラブルの原因となっているドライバーを特定し、使用を中止するか、カーネルハッカーになって修正する。
-
再起動せずに無停止プロセスを強制終了する方法:どういうわけか、システムコールを終了します。多くの場合、電源スイッチを押すことなくこれを行う最も効果的な方法は、電源コードを引くことです。 LWNの記事で説明されているように、カーネルハッカーになり、ドライバーにTASK_KILLABLEを使用させることもできます。
他のヒント
プロセスがユーザーモードの場合、いつでも中断できます(カーネルモードへの切り替え)。カーネルがユーザーモードに戻ると、保留中のシグナル( SIGTERM
や SIGKILL
など、プロセスの強制終了に使用されるシグナルを含む)があるかどうかを確認します。つまり、プロセスはユーザーモードに戻ったときにのみ強制終了できます。
プロセスをカーネルモードで強制終了できないのは、同じマシン内の他のすべてのプロセスが使用するカーネル構造を破損する可能性があるためです(スレッドを強制終了すると、他のスレッドが使用するデータ構造を潜在的に破損する可能性があります同じプロセス)。
カーネルは、長時間かかる可能性のある処理(別のプロセスによって書き込まれたパイプで待機する、またはハードウェアが処理するのを待つなど)を行う必要がある場合、スリープとしてマークし、スケジューラを呼び出すことでスリープします別のプロセスに切り替えます(スリープしていないプロセスがない場合、「ダミー」プロセスに切り替えます。このプロセスは、CPUに少し速度を落とし、ループ—アイドルループになります)。
シグナルがスリープ中のプロセスに送信された場合、ユーザー空間に戻って保留中のシグナルを処理する前に、ウェイクアップする必要があります。ここで、2つの主要な睡眠タイプの違いがあります。
-
TASK_INTERRUPTIBLE
、割り込み可能なスリープ。タスクがこのフラグでマークされている場合、タスクはスリープ状態になっていますが、シグナルによってウェイクアップできます。これは、タスクをスリープ状態としてマークしたコードが可能なシグナルを予期しており、ウェイクアップ後にそれをチェックし、システムコールから戻ることを意味します。シグナルが処理された後、システムコールが潜在的に自動的に再起動される可能性があります(そして、その仕組みについては詳しく説明しません)。 -
TASK_UNINTERRUPTIBLE
、割り込み不可能なスリープ。タスクがこのフラグでマークされている場合、タスクは簡単に再起動できないため、またはプログラムがシステムコールをアトミックであると予期しているため、待機しているもの以外によって起動されることを期待していません。これは非常に短いことがわかっている睡眠にも使用できます。
TASK_KILLABLE
(ddaaの回答にリンクされているLWN記事に記載)は新しい亜種です。
これは最初の質問に答えます。 2番目の質問について:割り込み不可能なスリープを避けることはできません。これは通常のことです(たとえば、プロセスがディスクの読み取り/書き込みを行うたびに発生します)。ただし、それらはほんの数秒しか続かないはずです。それらがはるかに長く続く場合、通常はハードウェアの問題(またはカーネルと同じように見えるデバイスドライバーの問題)を意味し、デバイスドライバーはハードウェアが決して起こらないことをするのを待っています。 NFSを使用していて、NFSサーバーがダウンしていることも意味します(サーバーが回復するのを待っています。問題を回避するために∫ intr"オプションを使用することもできます)。
最後に、回復できない理由は、カーネルがユーザーモードに戻ってシグナルを送信するかプロセスを強制終了するまで待機するのと同じ理由です:カーネルのデータ構造を破壊する可能性があります(割り込み可能なスリープで待機しているコードはエラーを受信できます)プロセスを強制終了できるユーザー空間に戻るように指示します。割り込み不可能なスリープを待機しているコードはエラーを予期していません。
割り込み不可能なプロセスは、通常、ページフォールト後のI / Oを待機しています。
これを考慮してください:
- スレッドは、コアにないページ(デマンドロードされた実行可能ファイル、スワップアウトされた匿名メモリのページ、またはデマンドロードされたmmap() 'dファイルにアクセスしようとします。ほぼ同じです)
- カーネルは現在(ロードしようとしています)ロードしています
- プロセスは、ページが利用可能になるまで続行できません。
プロセス/タスクはシグナルを処理できないため、この状態では中断できません。その場合、別のページフォールトが発生し、元の場所に戻ります。
「プロセス」と言うとき、私は本当に「タスク」を意味します。これはLinux(2.6)では「スレッド」に大まかに変換されます。個別の「スレッドグループ」を持つ場合と持たない場合があります。 / procのエントリ
場合によっては、長時間待機していることがあります。これの典型的な例は、実行可能ファイルまたはmmap'dファイルが、サーバーに障害が発生したネットワークファイルシステム上にある場合です。最終的にI / Oが成功した場合、タスクは続行します。最終的に失敗した場合、タスクは通常SIGBUSまたは何かを取得します。
3番目の質問:
私はあなたが実行することにより、中断できないプロセスを殺すことができると思います
sudo kill -HUP 1
。
実行中のプロセスを終了せずにinitを再起動し、実行後に中断できないプロセスがなくなりました。
「ゾンビ」について話している場合プロセス(ps出力で「ゾンビ」と指定されている)、これはプロセスリスト内の無害なレコードであり、誰かがそのリターンコードを収集するのを待っているため、無視しても問題ありません。
何と「割り込み不可能なプロセス」を説明してください。あなたのためです? " kill -9"を生き延びますか喜んで一緒に一気飲みしますか?その場合は、システムコールに引っかかっており、ドライバーに引っかかっており、再起動するまで(そしてすぐに再起動する方が良い場合がある)、または関連するドライバーをアンロードするまで(この可能性は低い) 。 「strace」を使用してみてください。プロセスの行き詰まりを見つけて、将来的にそれを避けるために。