私が理解している限り、カーネルはプロセスではなく、別の進行状況のランタイムから(またはタイマーなどを介してカーネル自体によって)呼び出すことができるハンドラーのセットです。
プログラムが再び実行を開始する前に長時間実行の同期処理を必要とする例外ハンドラーにヒットした場合(たとえば、ディスクの読み取りを必要とするページフォールトにヒットした場合)、カーネルはコンテキストを切り替える必要があることをどのように識別しますか?これを実現するには、別のプロセスを実行する必要があるように思われますか?
カーネルは、この状態のプロセスを断続的にチェックすることによってこれを処理するプロセスを生成しますか?長時間実行される同期ハンドラーを呼び出すプロセスは、ハンドラーが完了するまで(たとえば、ディスクの読み取りが完了するまで)コンテキストを切り替える必要があることをカーネルに通知しますか?
"カーネルはプロセスではありません。"
これは純粋な用語です。 (用語は重要です。)定義上、プロセスはユーザーランドに存在するため、カーネルはプロセスではありません。しかし、カーネルにはスレッドがあります。
"プログラムが、実行を再開する前に長時間実行の同期処理を必要とする例外ハンドラーにヒットした場合(たとえば、ディスク読み取りを必要とするページフォールトにヒットした場合)"。
ユーザーランドプロセスが、マップされていないメモリページを参照するマシン命令を実行する場合、次のようになります。
プロセッサはトラップを生成し、 リング0 /スーパーバイザモード に移行します。 (これはハードウェアで発生します。)
トラップハンドラーはカーネルの一部です。実際にメモリページをディスクからページインする必要があると仮定すると、プロセスは中断できないスリープ状態になります(つまり、プロセスのCPU状態がプロセステーブルに保存され、のテーブルのプロセスエントリのステータスフィールドが変更されます。プロセス)、ビクティムメモリページを見つけ、I/Oを開始してビクティムと要求されたページのページをページアウトし、スケジューラ(カーネルの別の部分)を呼び出して、ユーザーランドコンテキストを実行可能な別のプロセスに切り替えます。
最終的に、I/Oが完了します。これにより、割り込みが生成されます。割り込みに応答して、プロセッサはハンドラを呼び出し、リング0 /スーパーバイザモードに移行します。 (これはハードウェアで発生します。)
割り込みハンドラはカーネルの一部です。メモリページを待機していたプロセスのI/O待機状態をクリアし、実行の準備ができたことを示します。次に、スケジューラーを呼び出して、ユーザーランドコンテキストを実行可能なプロセスに切り替えます。
一般に、カーネルは次のように実行されます。
ハードウェアトラップまたは割り込みへの応答。これにはタイマー割り込みが含まれます。
ユーザープロセスからの明示的なシステムコールへの応答。
ほとんどの場合、プロセッサはリング3 /ユーザーモードであり、ユーザーランドプロセスからの命令を実行します。ユーザーランドプロセスがsyscallを行うと(たとえば、何らかの入出力操作を実行したいため)、またはハードウェアがトラップを生成すると(無効なメモリアクセス、除算)、リング0 /スーパーバイザーモード(カーネルが存在する場所)に移行します。ゼロなど)またはハードウェアから割り込み要求を受信したとき(I/O完了、タイマー割り込み、マウス移動、ネットワークインターフェイスにパケットが到着したなど)
タイトルの質問に答えるために、「カーネルスケジューラはプロセスをプリエンプトする方法をどのように知っていますか」:カーネルはタイマー割り込みを処理します。タイマー割り込みが到着したときに、現在実行中のユーザーランドプロセスがその quantum を使い果たしたことにシュデュラーが気付いた場合、プロセスは実行中のキューの最後に置かれ、別のプロセスが再開されます。 (一般に、スケジューラーは、実行の準備ができているすべてのユーザーランドプロセスがプロセッサー時間を公平に受け取るように注意を払います。)
プログラムが再び実行を開始する前に長時間実行の同期処理を必要とする例外ハンドラーにヒットした場合(たとえば、ディスクの読み取りを必要とするページフォールトにヒットした場合)、カーネルはコンテキストを切り替える必要があることをどのように識別しますか?これを実現するには、別のプロセスを実行する必要があるように思われますか?
ページフォールトでディスクの読み取りが必要な場合、カーネルページフォールトハンドラーはカーネルスケジューラを呼び出します。
https://elixir.bootlin.com/linux/v4.17/source/mm/filemap.c#L247
_filemap_fault()
wait_on_page_locked() - usually via __lock_page_or_retry()
wait_on_page_bit()
wait_on_page_bit_common()
io_schedule()
schedule()
_
これらの質問の意味はよくわかりませんが、2番目の質問に対する答えは「いいえ、必要ありません」だと思います。
最適化を無視すると、カーネルは常に読み取りをキューに入れた直後にコンテキストを切り替えます。 (つまり、これはfilemap_fault()
が__lock_page_or_retry()
を呼び出す前に発生します。ロジックはもう少し複雑ですが、クリックするのはそれほど難しくありません)。
他に実行可能なプロセスがない場合、カーネルはCPUをアイドルタスクに切り替えます。 (LinuxカーネルにはCPUごと アイドルスレッド があります。ただし、Windowsの「システムアイドルプロセス」とは異なり、たとえばtop
には表示されません)。