Linux内核零碎笔记
#中断下半部.
common_interrupt:
addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */ #调整中断号到0~255的范围.
SAVE_ALL
TRACE_IRQS_OFF
movl %esp,%eax
call do_IRQ #处理中断例程.
jmp ret_from_intr
ENDPROC(common_interrupt)
unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
/* high bit used in ret_from_ code */
unsigned vector = ~regs->orig_ax;
unsigned irq;
exit_idle();
irq_enter();
irq = __get_cpu_var(vector_irq)[vector];
if (!handle_irq(irq, regs)) { #调用对应的中断例程.
ack_APIC_irq(); #如果例程成功返回则回应8259A高级编程中断控制器.
if (printk_ratelimit())
pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n",
__func__, smp_processor_id(), vector, irq);
}
irq_exit(); #处理完中断上半部后,就调用irq_exit执行中断下半部.
set_irq_regs(old_regs);
return 1;
}
void irq_exit(void)
{
account_system_vtime(current);
trace_hardirq_exit();
sub_preempt_count(IRQ_EXIT_OFFSET);
if (!in_interrupt() && local_softirq_pending())
invoke_softirq(); #调用__do_softirq.
rcu_irq_exit();
#ifdef CONFIG_NO_HZ
/* Make sure that timer wheel updates are propagated */
if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
tick_nohz_stop_sched_tick(0);
#endif
preempt_enable_no_resched();
}
# define invoke_softirq() __do_softirq() #invoke_softirq是替换成__do_softirq的宏.
asmlinkage void __do_softirq(void)
{
struct softirq_action *h;
__u32 pending;
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu;
pending = local_softirq_pending(); #保存待处理的软中断的32位图到栈变量里.
account_system_vtime(current);
__local_bh_disable((unsigned long)__builtin_return_address(0));
lockdep_softirq_enter();
cpu = smp_processor_id();
restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0); #清零待处理的软中断的32位图.
local_irq_enable(); #当前CPU开启中断.
h = softirq_vec; #获取软中断数组的第一个元素.
do { #开始轮询软中断数组.好像是32个.
if (pending & 1) { #判断每一位,为1则说明该位对应的软中断需要处理.
int prev_count = preempt_count();
kstat_incr_softirqs_this_cpu(h - softirq_vec);
trace_softirq_entry(h, softirq_vec);
h->action(h); #处理相关软中断.
trace_softirq_exit(h, softirq_vec);
if (unlikely(prev_count != preempt_count())) {
printk(KERN_ERR "huh, entered softirq %td %s %p"
"with preempt_count %08x,"
" exited with %08x?\n", h - softirq_vec,
softirq_to_name[h - softirq_vec],
h->action, prev_count, preempt_count());
preempt_count() = prev_count;
}
rcu_bh_qs(cpu);
}
h++; #下一个.
pending >>= 1; #下一个.每检查一位就向右移,可见最低位的优先级最高.
} while (pending);
local_irq_disable(); #当前CPU屏蔽中断.
pending = local_softirq_pending(); #再获取一下待处理的软中断的32位图,看处理软中断期间是否又发生了软中断请求.
if (pending && --max_restart) #如果发生请求并且在单次处理软中断的最大循环检查次数内.
goto restart; #则跳到restart处,再处理新来的软中断.可见软中真是响应的非常及时呀.
if (pending) #如果如果软中断的次数确实太频繁了.
wakeup_softirqd(); #则唤醒专门处理软中断的内核线程.
lockdep_softirq_exit();
account_system_vtime(current);
_local_bh_enable();
}
#软中断_32位的位图判断 并行(SMP情况下同时处理) 内核线程辅助检测软中断位图 不可睡眠
#tasklet