割り込みが発生すると、割り込みハンドラーに入ります。
ただし、割り込みハンドラは、ハードウェアに 迅速に応答して、タイム クリティカルな操作を完了できるように、高速、非同期、シンプルである必要があります。
したがって、時間要件が比較的緩やかな他のタスクについては、実行する前に、割り込みがアクティブになるまで 延期する必要があります。 このように、割り込み処理プロセス全体は 2 つの部分
:最初の部分は割り込みハンドラー (
そして
中断と回復の後、 を実行できます。 上半分と下半分の主な違い:
上半分
は、割り込みに関連しているものの、延期できるいくつかのタスクを指します。 割り込みの上半分は同じ種類の割り込みによって割り込むことはできませんが、下半分は引き続き割り込みによって割り込まれる可能性があります
。#通常、下半分は割り込みハンドラーが返されるとすぐに実行されます。
前半はシンプルで高速です
、実行中の一部またはすべての割り込みを無効にします。#後半は後で実行されます。実行中にすべての割り込みに応答できます。
Linux
では、割り込みの下半分を実装する主な方法が 3 つあります。
は Softirq で、コードは kernel/ にあります。 Softirq.c
ファイル内; 各 Softirq は
構造によって表されます: softirq の
Softirq ベクトル配列 softirq_vec
が定義されています。 <pre class="brush:php;toolbar:false;">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_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ, /*用于低优先级的tasklet*/
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};</pre>
配列のメンバーの数は、列挙定数である
によって決まります。 ソフト割り込みを追加する場合、ファイル
に列挙定数を追加する必要があります。
: 相关接口 即注册对应类型的处理函数到全局数组 实际上即以软中断类型 这也是同一类型软中断可以在多个 以一个按键驱动的中断处理为例,将按键驱动的中断处理分成上下两部分: 許可なくソフト割り込み の数を増やすことはお勧めしません。新しいソフト割り込みが必要な場合は、 ソフト割り込みベースの として実装するようにしてください。タスクレット は、ソフト割り込み#を使用します。 ## 実装された下半分のメカニズムの一種です。 ソフト割り込みと のどちらを使用する方が良いですか? のどちらを使用するかを選択するのは、実際には非常に簡単です: 1、编写 2、声明 3、调度 登记 以按键中断驱动为例: まず、 2 つの重要なポイント: ワーク キューの関連インターフェイス関数: ワークキューはタスクレット
void open_softirq(int nr, void (*action)(struct softirq_action *))
softirq_vec
中。void raise_softirq(unsigned int nr)
nr
作为偏移量会置位irq_stat[cpu_id]
的成员变量__softirq_pending
.__softirq_pending
字段中的每一个bit
,对应着某一个软中断,某个bit
被置位,说明有相应的软中断等待处理。cpu
上并行运行的根本原因。
软中断实例
#ソフト割り込みの登録、ドライバーのエントリ関数で、ソフト割り込みを登録します:
追加された列挙型定数:
ご覧のとおり、ソフト割り込みを使用するにはカーネルを変更する必要があり、列挙型の追加は少し面倒です。 したがって、通常は フォーム。
タスクレット
##タスクレットsoftirq
と
tasklet
。就像我们在前面看到的,软中断资源有限,也麻烦,而且软中断的使用者屈指可数。它只在那些执行频率很高和连续性要求很高的情况下才需要。tasklet
效果都不错,而且它们还非常容易使用。
tasklet使用
tasklet
的使用步骤如下:tasklet
处理函数(下半部)void my_tasklet_fun (unsigned long data)
tasklet
//静态
DECLARE_TASKLET(my_tasklet,my_tasklet_fun,data);
//动态
Struct tasklet_struct xxx;
tasklet_init(&xxx,tasklet_handler,dev)
tasklet
tasklet_schedule(&my_tasklet);
my_tasklet
, 然后允许系统在合适的时间调度它。
tasklet实例
DECLARE_TASKLET
を使用して tasklet
を静的に宣言し、その下位半分の関数を btn_tasklet_func
として指定し、タスクを中断します。 service 関数 (上半分) はキー値を取得した後、tasklet_schedule
scheduling を呼び出します。
ワーク キュー
ワーク キュー
は ワーク キュー、下半分に割り込むタイプでもあります。 ワーク キュー
作業の後半を カーネル スレッド に実行を延期します - work
は常に プロセス コンテキストで実行されます.
work queues
を使用します。それ以外の場合は、softirq
または tasklets
を使用します。Work queues
は、大量のメモリを割り当てて、セマフォ. 、またはブロックされた I/O
.に似ています:
以上がLinux ドライバーの下半分を中断する 3 つの方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。