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