Linuxのカーネルソフトブレーク(softirq)実行分析
12516 ワード
本文はLinuxカーネルのソフトブレークの実行プロセスを分析し、できるだけ現在の実行環境と結びつけて私の理解を詳しく書いたが、これは私の理解が正しいことを示していない.これはフォーラムの中の1篇の招待状で、出すのはレンガを投げて玉を引くためで、もしあなたが本文を読む時私の間違いを発見したら、またあなたの指摘を得ることを望みます.
今日は何気なく目2.6コアのソフトブレーク実装を見て、以前私が見たのとは大きく異なることに気づきました(以前も馬鹿げていて、あまり注意していません)、大きく変わったと言えます.softirqの呼び出しポイントまで違います.以前は3つの呼び出しポイントでしたが、今日ソースコードを検索してみると、ksoftirqdが多くなった後、softirqのシステムでの呼び出しポイントはISRの戻り時とlocal_を使用しただけです.bh_enable()関数が呼び出されました.NIC部分の表示呼び出しは、システム内の呼び出しポイントではないと思います.ksoftirqdはdo_を呼び出すために戻りますsoftirq()関数もそのうちの1つの分岐としか言えないはずです.それ自体はソースから言えばISRが戻ったときのirq_であるからです.exit()呼び出しです.これで先日書いたノート(Windows/Linux)と
/Solarisソフト割り込みメカニズム)で紹介されているLinuxカーネル部分のソフト割り込みには出典がありますが、今後Linux kernelコードを議論するには必ずカーネルバージョンを前題にしなければならないようです.Linux側の本を買わなければなりません.毎回直接関連コードを読むのも問題ではありません.時間も許されません.
今日は何気なく目2.6コアのソフトブレーク実装を見て、以前私が見たのとは大きく異なることに気づきました(以前も馬鹿げていて、あまり注意していません)、大きく変わったと言えます.softirqの呼び出しポイントまで違います.以前は3つの呼び出しポイントでしたが、今日ソースコードを検索してみると、ksoftirqdが多くなった後、softirqのシステムでの呼び出しポイントはISRの戻り時とlocal_を使用しただけです.bh_enable()関数が呼び出されました.NIC部分の表示呼び出しは、システム内の呼び出しポイントではないと思います.ksoftirqdはdo_を呼び出すために戻りますsoftirq()関数もそのうちの1つの分岐としか言えないはずです.それ自体はソースから言えばISRが戻ったときのirq_であるからです.exit()呼び出しです.これで先日書いたノート(Windows/Linux)と
/Solarisソフト割り込みメカニズム)で紹介されているLinuxカーネル部分のソフト割り込みには出典がありますが、今後Linux kernelコードを議論するには必ずカーネルバージョンを前題にしなければならないようです.Linux側の本を買わなければなりません.毎回直接関連コードを読むのも問題ではありません.時間も許されません.
//
// do_IRQ ISR 。
//
void irq_exit(void)
{
account_system_vtime(current);
trace_hardirq_exit();
sub_preempt_count(IRQ_EXIT_OFFSET);
//
// ,
// pending , :
// , do_softirq() 。
// ,
// 。
//
if (!in_interrupt() && local_softirq_pending())
//
// do_softirq()
//
invoke_softirq();
preempt_enable_no_resched();
}
#ifndef __ARCH_HAS_DO_SOFTIRQ
asmlinkage void do_softirq(void)
{
__u32 pending;
unsigned long flags;
//
// , ,
// , 。
// ksoftirqd 。
//
if (in_interrupt())
return;
//
//
//
local_irq_save(flags);
//
// pending 。
//
pending = local_softirq_pending();
//
// __do_softirq()
//
if (pending)
__do_softirq();
//
//
//
local_irq_restore(flags);
}
//
// 10 。
//
#define MAX_SOFTIRQ_RESTART 10
asmlinkage void __do_softirq(void)
{
//
// , ISR
// 。
//
struct softirq_action *h;
__u32 pending;
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu;
//
// pending 。
//
pending = local_softirq_pending();
account_system_vtime(current);
//
// ,
// CPU 。
//
__local_bh_disable((unsigned long)__builtin_return_address(0));
trace_softirq_enter();
//
// SMP CPU
//
cpu = smp_processor_id();
//
//
//
restart:
//
// ISR ,
// 。
//
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
//
// , :
// , 。
// 。
// 。
//
local_irq_enable();
//
// , ,
// ISR , ,
// , , __local_bh_disable()
// 。 ,
// 。 ,
// __local_bh_disable() ,
// irq_exit() do_softirq()
// in_interrupt() , in_interrupt()
// 。
// , ,
// , ( MAX_SOFTIRQ_RESTART)
// 。
//
//
// 。
//
h = softirq_vec;
//
// softirq 。
//
do {
//
// pending
// 。
//
if (pending & 1) {
//
// 。
//
h->action(h);
rcu_bh_qsctr_inc(cpu);
}
//
// , pending
// 。
//
h++;
//
// ,
// 32 。
//
pending >>= 1;
} while (pending);
//
// 。 : ,
// 。
//
local_irq_disable();
//
// ,
// , ,
// ,
// , 。
// restart 。
//
pending = local_softirq_pending();
//
// ,
// , pending ,
// ,
// , irq_exit() do_softirq()
// 。 。
// 。 :
// ,
//
// , ,
// ISR 。
//
//
// ,
// 10 , restart
// : , ...
// : 。
//
if (pending && --max_restart)
goto restart;
//
// 10 pending ,
// , 。
// ksoftirqd ,
// 。 ksoftirqd ,
// , ,
// , preempt_xxx() schedule()
// 。
// local_softirq_pending() pending
// , do_softirq()
// 。 , ksoftirqd
// ,
// , do_softirq(), do_softirq()
// in_interrupt()
// , 。ksoftirqd
// ksoftirqd() 。
//
if (pending)
//
// wake_up_process() ksoftirqd
//
wakeup_softirqd();
trace_softirq_exit();
account_system_vtime(current);
//
// , 。 :
// local_bh_enable(), do_softirq()
// 。
//
_local_bh_enable();
}
static int ksoftirqd(void * __bind_cpu)
{
//
// 。 ,
// 。
//
set_user_nice(current, 19);
//
//
//
current->flags |= PF_NOFREEZE;
//
// ,
// 。
//
set_current_state(TASK_INTERRUPTIBLE);
//
// , ,
// pending
// 。
//
while (!kthread_should_stop()) {
//
// ,
// 。
//
preempt_disable();
//
// pending
//
//
if (!local_softirq_pending()) {
//
// CPU ,
// 。
//
preempt_enable_no_resched();
//
// CPU ,
// ( )
//
schedule();
//
// : schedule()
// ,
// 。 ,
// , preempt_disable() 。
//
//
// ,
// 。
//
preempt_disable();
}
//
// 。 :
// , 。
// pending 。
// pending , CPU
// 。
//
__set_current_state(TASK_RUNNING);
//
// pending , do_softirq()
// 。 : do_softirq() ,
// __do_softirq() 10
// , pending , 。
// __do_softirq() 。
// __do_softirq() , 10
// 。 ,
// , do_softirq() ,
// CPU , cond_resched()
// ,
// CPU ,
// CPU。
//
while (local_softirq_pending()) {
/* Preempt disable stops cpu going offline.
If already offline, we'll be on wrong CPU:
don't process */
if (cpu_is_offline((long)__bind_cpu))
//
// CPU
// wait_to_die , 。
//
goto wait_to_die;
//
// do_softirq() 。
// : ,
// , in_interrupt() 。
//
do_softirq();
//
// 。
//
preempt_enable_no_resched();
//
// schedule()
// , 。
// ,
// 。
// CPU,
//
// 。
//
cond_resched();
//
// 。
//
preempt_disable();
//
// ?
//
}
//
// , ,
// , 。
//
preempt_enable();
set_current_state(TASK_INTERRUPTIBLE);
}
//
// 。
// 。
//
__set_current_state(TASK_RUNNING);
return 0;
//
//
//
wait_to_die:
//
// 。
//
preempt_enable();
/* Wait for kthread_stop */
//
// ,
// 。
//
set_current_state(TASK_INTERRUPTIBLE);
//
// ,
// CPU
// 。
// 。
//
while (!kthread_should_stop()) {
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
//
// 。
// 。
//
__set_current_state(TASK_RUNNING);
return 0;
}