システムコールは、ソフトウェア割り込みハンドラー全体のコンテキストで実行されますか?
つまり、read()のような一部のシステムコールは、ISRの実行時間を非常に短くする必要があるというポリシーに反して、戻るのに長い時間がかかる可能性があります。システムコールは他のスレッドにオフロードされていますか?それはどのように機能しますか?
[任意のカーネルへの参照は問題ありません]
システムコールは、ソフトウェア割り込みハンドラー全体のコンテキストで実行されますか?
つまり、read()のような一部のシステムコールは、ISRの実行時間を非常に短くする必要があるというポリシーに反して、戻るのに長い時間がかかる可能性があります。システムコールは他のスレッドにオフロードされていますか?それはどのように機能しますか?
[任意のカーネルへの参照は問題ありません]
システムコールが通常どのように機能するかについてのこの引用テキストをお読みください。
システムコールハンドラは、ユーザープログラムがシステムコールを開始すると制御を取得します。システムコールハンドラは、保護ドメインを発信者保護ドメインであるユーザーからシステムコール保護ドメインであるカーネルに変更し、保護されたスタックに切り替えます。
次に、システムコールハンドラは、システムコールをサポートする関数を呼び出します。ローダーは、この目的のために現在定義されているシステムコールのテーブルを維持します。
システムコールは呼び出しプロセス内で実行されますが、呼び出しプロセスよりも多くの特権があります。これは、保護ドメインがユーザーからカーネルに変更されたためです。
システムコール関数は、操作が完了するとシステムコールハンドラに戻ります。次に、システムコールハンドラはプロセスの状態を復元し、ユーザープログラムに戻ります。
現在、システムコール中のコンテキストスイッチングに関しては2種類のカーネルがあります。プリエンプティブカーネルと非プリエンプティブカーネル(大まかに言えば、これはコードのクリティカルセクションを実行するスレッド/プロセスにも適用されることがあるため)。
前者はRTOS(リアルタイムOS)で一般的ですが、後者は私たちが知っている最も一般的なOSで一般的です。
プリエンプティブカーネルでは、スケジューラは、システムコールを実行するスレッドをオプトアウトして、優先度の高いスレッドを優先することができます。後者では、次のように、この種のプリエンプションは許可されません。スレッドが現在システムコールを実行している場合、他のすべてのスレッドはカーネルモードの作業が完了するまで待機する必要があります。
要約すると、通常、非RTシステムでは、スレッドがシステムコールを実行する場合、スレッドはディスパッチされる前にその作業を終了する必要があります。
ここで何かに注意してください。一部のシステムコールがブロックしている可能性があります。
これは何を意味するのでしょうか?つまり、割り込みが発生するまで停止し、その後、作業が完了するまで実行に戻ります。
その一例がread()で、ユーザーが要求するデータの準備ができるまでブロックします。その間、他のスレッドの実行をスケジュールできますが、そのread()に割り込みが発生すると、再び実行が開始され、結果がユーザーランドに戻るまで、誰もそれをディスパッチできません(これもプリエンプティブでない環境でのみ)。
システムコールは、 ISR内のほとんどのカーネルで実行されます。Linuxの以前のリリースをざっと見てみるとint $Ox80
、カーネルを呼び出すことがわかります。カーネル開発の観点からおそらく最も単純なこのソリューションには、大きな欠点があります。ISRを実行している限り。割り込みは無効になっています。システムが反応しないことは明らかであるため、割り込みを無効にすると、時間がかかりすぎます(外部イベントが遅延し、時間どおりに再スケジュールされません...)。
アデルが彼の答えで説明したように、プリエンプションは賢い解決策です。しかし、カーネルがリソースを利用できないためにスレッドをプリエンプションすることを選択した場合は常に、割り込みを無効にしてすでに多くの時間を費やしています。
システムコールは他のスレッドにオフロードされていますか?
あなたが正しい。割り込みスレッドおよび/またはスレッドカーネルは、さらにスマートなソリューションです。SolarisやMacOSXのようなカーネルは、優先度の高い割り込みスレッドをウェイクアップするだけの非常に単純なISRを好む。したがって、ISRは最小限の処理に削減され、割り込みを無効にしてシステムを実行する時間が大幅に短縮されます。これらの割り込みスレッドは優先度が高いため、ISRの戻り時に実行される可能性があります。良いのは、割り込みが再び有効になるため、さらに優先度の高い作業が遅れることがないことです。最近のリリースのLinuxなどのスレッドカーネルでは、カーネル内で複数のことを実行でき、1つのブロックにもかかわらず、他のプロセスがカーネルに入ることができます。
この助けを願っています!
まず、Linuxで使用されるいくつかの用語。Linuxでは、カーネルはいくつかのコンテキストで実行できます。
/proc
ます...システムコールは、割り込みを有効にして実行を開始します(明示的に再度有効にした場合(たとえば、x86を使用する場合sysenter
)、またはまったく無効にしないため(たとえば、Linuxが行うx86のトラップゲートを使用する場合int 0x80
))。そのため、カーネルはシステムコールの実行中に割り込みによって割り込まれる可能性があります。
一部のシステムコールは、何かを待ってスリープ(ブロック)する場合があります。その場合、カーネルは別のタスク(プロセス/スレッド)に切り替えることができ、スリープ状態のタスクは後でウェイクアップされます。
非プリエンプティブカーネルでは、タスクは、プロセスコンテキストで実行されている(つまり、実際に作業を行っており、スリープしていない)別のタスクをプリエンプションすることはできません。プリエンプティブカーネルでは、優先度の高いタスクは、非アトミックプロセスコンテキストで実行されている優先度の低いタスクをプリエンプションできます。これにより、コンテキストスイッチの待ち時間が長くなるのを防ぎます。たとえば、オーディオプログラムを頻繁にスケジュールする必要がある場合、プリエンプティブカーネルにより、他のタスクの重いシステムコール処理がこれに干渉するのを防ぎます(オーディオアーティファクト、クリックなどが発生する可能性があります)。