記事のディレクトリ
前書き
前回の記事で、割り込みは非常に重要なメカニズムであり、割り込みハンドラーは割り込みコンテキストで実行されるだけでなく、他の割り込みも禁止するため、より高速に実行する必要があると述べました。実行が完了した後は、次のことも行う必要があります。システムの効率をある程度決定するペリフェラルに情報を返します。また、より多くの作業を完了できることを望んでいます。これは、明らかに前のコードと矛盾する、より多くのコードを意味します。今回は下半分のメカニズムが導入されており、その名のとおり下半分の実行ですが、実は上半分に時間制限の厳しい作品を与え、重要度の低いものを置くことです。下半分で上半分を改善するパートプログラムの応答速度。
ネットワークカードを例にとると、ネットワークカードがデータパケットを受信すると、割り込みがトリガーされます。明らかに、TCPウィンドウがメッセージのサイズを決定するため、ネットワークカードはデータができるだけ早く処理されることを望んでいます。次回受信した場合、データ処理が遅すぎると、全体的なデータ伝送速度が遅くなり、スループットが低下します。たとえば、ネットワークパケットのレイヤーごとの分解は上半分には配置されません。上半分に必要なのは、データをコピーしてネットワークカードに返信することだけです。
一般に、割り込みハンドラーの上半分のみを使用すると、次の欠点があります。
- 割り込みハンドラは非同期で実行されます。通常、他のプログラムの実行を中断します。中断されたプログラムの実行時間が長すぎるのを避けるために、割り込みハンドラはできるだけ速く実行する必要があります。
- IRQF_DISABLEDが設定されていない場合、この割り込みのみがシールドされます。設定されている場合、このプロセッサ上の他のすべての割り込みがシールドされるため、割り込みハンドラはできるだけ速く実行する必要があります。
- 割り込みハンドラーは割り込みコンテキストで実行されます。つまり、割り込みハンドラーはブロックされた関数を使用できず、アクションの範囲が制限されます。
- 割り込みハンドラはハードウェア上で動作する必要があるため、通常は高い時間制限が必要です。
以上の理由から、オペレーティングシステムは、割り込み処理プログラムの効率を向上させ、実行できる機能を増やすために、比較的時間要件の緩い処理プログラムを対象とした実行プログラムの下部を導入しました。
下半分に割り込み処理を実装する方法はたくさんあり、それぞれに独自の利点があります。カーネルバージョン2.6には、次のようなものがあります。
- ソフト割り込み
- タスクレット
- ワークキュー
ここには興味深い誤解があります。多くの人が下半分をソフト割り込みと呼んでいます。つまり、上記の下半分の実装の1つと、下半分全体をソフト割り込みと呼びます。しかし、これは同じことではありません。ソフト割り込み、タスクレット、ワークキューは密接に関連しています。
ソフト割り込みsoftirq
ソフト割り込みコードはkernel / softirq.cにあります。
ソフト割り込みメカニズムは静的メカニズムであり、32個のsoftirq_action構造体を含む配列です。softirq_action構造体は次のとおりです。
struct softirq_action
{
void (*action)(struct softirq_action *);
void *data;
};
ソフト割り込みは別の異なるソフト割り込みをプリエンプトしませんが、同じソフト割り込みプログラムが異なるプロセッサで同時に実行される可能性があることは言及する価値があります。つまり、データの同時アクセスに特別な注意を払う必要があります。ソフト割り込みをプリエンプトできるのは、割り込みハンドラだけです。ビットマップマーキング方式を使用したソフト割り込みの実行は非常に興味深いものです。まず、ソフト割り込みをいつ実行する必要があるかを判断する必要があります。次の場所で、トリガーされたソフト割り込みがチェックされ、実行されます。
- 割り込みハンドラから戻るとき。
- ksoftirqdカーネルスレッド(タスクレットに関連)。
- ネットワークサブシステムなど、保留中のソフト割り込みをチェックして実行するコードを表示します。
ソフト割り込みをマークする方法は?ソフト割り込みはビットマップを使用して、次の実行操作で実行される特定のソフト割り込みをマークすることを前述しました。ソフト割り込みメカニズムは静的であり、intはすべてのトリガー情報を保存します。
<Linux / interrupt.h>に列挙変数を追加することでソフト割り込みを静的に宣言しopen_softirq
、すでに宣言されているソフト割り込みを登録してraise_softirq
、後でソフト割り込みをトリガーできるようにすることができます。トリガーされdo_softirq
たソフト割り込みが実行されます。次回実行されるとき。
タスクレット
実際、タスクレットも一種のソフト割り込みであり、実装上、タスクレットは登録されたソフト割り込みの1つであるため、実際にはタスクレットも一種のソフト割り込みですが、タスクレットは何らかの特殊な手段で動的拡張を実現します。32を超えるソフト割り込みハンドラーを使用できます。もちろん、他にも違いがあります。これについては後で説明します。
では、タスクレットはどのように実装されますか?ソフト割り込み記述子テーブルを見てみましょう。
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
enum
{
HI_SOFTIRQ=0, /*用于高优先级的tasklet*/
TIMER_SOFTIRQ, /*用于定时器的下半部*/
NET_TX_SOFTIRQ, /*用于网络层发包*/
NET_RX_SOFTIRQ, /*用于网络层收报*/
BLOCK_SOFTIRQ, /*block装置*/
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ, /*用于低优先级的tasklet*/
SCHED_SOFTIRQ, /*调度程序*/
HRTIMER_SOFTIRQ, /*高分辨率定时器*/
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};
HI_SOFTIRQ
合計BLOCK_SOFTIRQ
は、実際にはタスクレットの実装に使用されるソフト割り込みテーブルエントリであることがわかります。
特定の実装プロセスは、スケジュールされたタスクレットを2つのtasklet_struct構造体のリンクリストに配置することです。登録は、リンクリストに構造体を挿入することであり、実行は、リンクリストの1つですべてのコールバックを実行することです。task_struct構造体を見てみましょう。
struct tasklet_struct
{
struct tasklet_struct *next; // 链表中的下一项
unsigned long state; // tasklet的状态
atomic_t count; // 引用计数器
void (*func)(unsigned long); // 回调函数
unsigned long data; // 给tasklet处理函数的参数
};
タスクレットがされ、スケジュールによるtasklet_schedule
とtasklet_hi_schedule
、彼らはリンクリストにtasklet_structを挿入することができ、実行時に各アイテムにコールバック関数を実行することができます。タスクレットが実行されると、各項目のステータスがチェックされ、同じコードが同時に実行されないようにすることができますが、これはステータスでロックする必要があります。
では、タスクレットの具体的な実行プロセスは何ですか?
- do_softirqを実行して、トリガーされたソフト割り込みハンドラーを実行します。
- 割り込みを無効にします。
- プロセッサ上の対応するリンクリストをNULLに設定します。
- ループして、各タスクレットを処理します。
- マルチプロセッサシステムの場合は、状態をチェックして、他のプロセッサで実行されているかどうかを確認します。
- 実行されない場合は、TASKLET_STATE_RUNを設定して、他のプロセッサがこのタスクレットを実行できないようにします。
- カウントをチェックして、タスクレットが禁止されていないことを確認します。
- リンクリストが空になるまで、上記のようにタスクレットを実行します。
シンプルで効果的なメカニズムが私たちのニーズを満たします。
ただし、処理関数が再トリガーされて再度実行される場合があるという問題があります。トリガーされたすべての割り込みがこの割り込みで直接実行されるか、次の割り込みがトリガーされたときに実行されるという2つの解決策があります。これら2つの方法には、それぞれ独自の欠点があります。
前者を使用すると、負荷が高いときにシステムが常に中断され、ユーザースペースタスクが無視されます。ユーザーの負荷が低い場合、次の割り込みが戻ったときにトリガーされます。つまり、しばらく待つ必要があります。したがって、開発者はこれら2つの場所の間で妥協する必要があります。この計画はksoftirqd
です。
保留中のソフト割り込みがある限り、各プロセッサにはスレッドがあり、ksoftirqdはdo_softirq()を呼び出してそれらを処理します。これにより、上記の問題が回避されます。
ワークキュー作業メカニズム
これは、ソフト割り込みから作業の延期とはまったく異なるメカニズムです。ソフト割り込みとの最大の違いは、ソフト割り込みが割り込みコンテキストで実行され、ワークキューがプロセスコンテキストで実行されることです。つまり、操作範囲がはるかに広くなります。ブロッキング操作ができるからです。詳細は説明していませんので、[1]をご参照ください。
選び方
まず、ソフト割り込みメカニズムはシリアル化を保証しません。つまり、データのセキュリティを確保するためにいくつかの手順を実行する必要があります。これは時間の無駄ですが、ネットワークサブシステムなど、コード自体をより高度にすると、Soft割り込みは良い選択です。全体として、ソフト割り込みは、厳しい時間要件と高い実行頻度を持つアプリケーションに適しています。
タスクレットも一種のソフト割り込みであり、数に上限はなく、同じタイプの2つのタスクレットが同時に実行されることはありません。これにより、各タスクレットでデータが競合することもなくなります。したがって、割り込みコンテキストで実行する必要があり、時間要件が厳密でない場合は、タスクレットを使用できます。
最初の2つには非常に致命的な問題があります。つまり、割り込みコンテキストでのみ実行できます。割り込みコンテキストにはブロックされた関数を実行する方法がないため、ソフト割り込みで実行できることが制限されます。ワークキューはで実行できます。これらの問題を解決するためのプロセスコンテキスト。しかし、効率は低いです。
ここには、割り込みがソフト割り込みをプリエンプトでき、ソフト割り込みがプロセスのコンテキストで実行されているコードをプリエンプトできるため、あいまいな問題、つまりロックの問題があります。したがって、プロセスのコンテキストが下半分とデータを共有する場合、データにアクセスする前に禁止する必要があります。処理の下半分とロックを使用する権利を取得します。下部の共有データにアクセスする前に、割り込みを禁止し、ロックの制御を取得する必要があります。そうしないと、デッドロックが発生する可能性があります。
参照:
- ブログ投稿「workqueue(workqueue)」
- 「Linuxカーネルの設計と実装」を予約する
- ブログ投稿「Linuxカーネルのメカニズムの下半分のタスクレット」
- ブログ投稿「プロセスの後半のタスクレットを中断する」