#author("2017-10-16T01:31:14+09:00","default:afuruta","afuruta")
#author("2017-10-16T10:57:56+09:00","default:afuruta","afuruta")
* softirq 処理はいつ行われるのか [#i85da92c]
softirq に登録 (&ogdefs(open_softirq());) した関数が &ogdefs(raise_softirq());, &ogdefs(raise_softirq_irqoff()); で実行保留状態になった後、実行される状況は次の表のとおりです。tasklet, timer とも softirq に登録した関数の処理として実装されているので、これらが実行される状況だとも言えます。

|イベント・呼び出し|CENTER:呼び出し元 contextで処理されるか?|CENTER:irq 処理の最後で処理されるか?|CENTER:ksoftirqd で処理されるか?|h
|割り込み発生&br;(&ogdefs(irq_exit());)|CENTER:-|CENTER:×: &ogdefs(in_interrupt());&br;○: (!&ogdefs(in_interrupt());)&sup([*1]);&sup([*2]);&sup([*4]);|CENTER:×: &ogdefs(in_interrupt());&br;○: (!&ogdefs(in_interrupt());)&sup([*1]);&sup([*2]);&sup([*4]);|
|&ogdefs(do_softirq());|CENTER:×: &ogdefs(in_interrupt());&sup([*3]);&br;○: (!&ogdefs(in_interrupt());)&sup([*2]);|CENTER:-|CENTER:×: &ogdefs(in_interrupt());&sup([*3]);&br;○: (!&ogdefs(in_interrupt());)&sup([*2]);|
|&ogdefs(raise_softirq());&br;&ogdefs(raise_softirq_irqoff());|CENTER:×|CENTER:-|CENTER:×: &ogdefs(in_interrupt());&sup([*3]);&br;○: (!&ogdefs(in_interrupt());)|
○: 処理する。×: 処理しない。-: 組み合わせ上の空き。

&sup([*1]); &ogrefs(CONFIG_IRQ_FORCED_THREADING); が定義されて構築された kernel に起動パラメータ &ogdefs(threadirqs,setup_forced_irqthreads); が付加されている場合は、ksoftirqd で softirq 処理が行われます。&ogrefs(CONFIG_IRQ_FORCED_THREADING); が定義されていないか、定義されて構築された kernel に起動パラメータ &ogdefs(threadirqs,setup_forced_irqthreads); が付加されていない場合は、softirq 処理に時間が掛かった場合、処理しきれない分を ksoftirqd にて処理する。
&sup([*1]); &ogrefs(CONFIG_IRQ_FORCED_THREADING); が定義されて構築された kernel に起動パラメータ &ogdefs(threadirqs,setup_forced_irqthreads); が付加されている場合は、ksoftirqd で softirq 処理が行われます。&ogrefs(CONFIG_IRQ_FORCED_THREADING); が定義されていないか、定義されて構築された kernel に起動パラメータ &ogdefs(threadirqs,setup_forced_irqthreads); が付加されていない場合は、softirq 処理に時間が掛かった場合、処理しきれない分を ksoftirqd にて処理します。

&sup([*2]); 割り込み処理の最後または、呼び出したコンテキスト中で制限時間 &ogdefs(MAX_SOFTIRQ_TIME); または、繰り返し制限回数 &ogdefs(MAX_SOFTIRQ_RESTART); 以内に終わらなければ、ksoftirqd thread で処理されます。

&sup([*3]); &ogdefs(in_interrupt()); が真の場合、実行されません。&ogdefs(in_interrupt()); は &ogdefs(irq_count()); で (&ogdefs(preempt_count()); & (&ogdefs(HARDIRQ_MASK); | &ogdefs(SOFTIRQ_MASK); | &ogdefs(NMI_MASK));) という実装がされています。ハードウエア割り込みの許可禁止関数、softirq の許可禁止関数を操作した結果による許禁止状態も &ogdefs(in_interrupt()); の結果に反映されています。

&sup([*4]); &ogdefs(irq_exit()); 内で直前にある &ogdefs(preempt_count_sub()); にて割り込み処理中状態から脱出する(カウンタを減じる)処理があります。殆どの状況で (!&ogdefs(in_interrupt());) が真になります。 

** ksoftirqd はいつ働く [#hf00b1ba]

softirq 処理のために ksoftirqd thread が用意されています。&ogrefs(ksoftirqd,ksoftirqd,softirq.c);, &ogdefs(softirq_threads); 変数で状態を保持しています。&span(ConsoleIn){ps uaxww}; コマンドでプロセスリストを表示すると ksoftirqd/0, ksoftirqd/1, ... のような名前で CPU の数と同じ数だけ並ぶ kernel thread です。
#code(c,/softirq_threads/../^};$/,ogfileone:/kernel/softirq.c);
softirq 処理が ksoftirqd で行われるのは &ogdefs(threadirqs,setup_forced_irqthreads); kernel parameter 未指定(または無効)で低負荷状態では稀です。ksoftirqd が使われる条件は &ogdefs(__do_softirq()); に実装されています。

割り込み処理の最後で softirq を処理する時間は 2ms (&ogdefs(MAX_SOFTIRQ_TIME);), softirq 処理中に新たに保留状態になった softirq を処理し尽くす様に繰り返す回数は 10 回 (&ogdefs(MAX_SOFTIRQ_RESTART);) になっています。これを超えた場合は、ksoftirqd thread の中で実行されることになります。コメントを読むと、経験的に決まった値のようです。割り込み応答時間を短くしたいならば、調整の余地がありそうな定数でしょう。
#code(c,/We restart softirq processing/../#.*MAX_SOFTIRQ_RESTART/,begin-=1,ogfileone:/kernel/softirq.c);
&ogdefs(__do_softirq()); 関数中にある &span(Code){h->action(h);}; が softirq 処理関数呼び出しです。保留している softirq 処理が残り続けると restart: ラベルを回るループが回ります。ループは &ogdefs(MAX_SOFTIRQ_TIME);, &ogdefs(MAX_SOFTIRQ_RESTART); で回る回数が制限され、制限に達すると &ogdefs(wakeup_softirqd()); が呼ばれ残りは ksoftirqd thread で行われます。
#code(c,/void __do_softirq/../^}$/,end+=1,ogfileone:/kernel/softirq.c);

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS