本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
在Linux kernel中,软中断在同一个CPU上,只能有一个运行实例。本文主要讲解Linux kernel是如何实现这个软中断特征的。
所有的软中断处理函数都是由do_softirq->__do_softirq调用的。所有只要保证一个CPU上只可能运行一个do_softirq实例,就保证了软中断只可能在同一CPU上存在一个实例。
在__do_softirq中,会调用__local_bh_disable去disable 软中断
- static inline void __local_bh_disable(unsigned long ip)
- {
- add_preempt_count(SOFTIRQ_OFFSET);
- barrier();
- }
该函数的实现是增加current_thread_info()->preempt_count的软中断部分的计数。
通过增加这个计数,保证了该进程不会被调度出去,那么软中断的执行序列一般就不会被打断,可以线性执行,也就保证了一个软中断的实例。但是如果发生中断,就会打断当前的软中断。而中断函数返回时,也是软中断的一个调用点。
我们来看看kernel是如何处理这种情况的。
- void irq_exit(void)
- {
- ...... ......
- if (!in_interrupt() && local_softirq_pending())
- invoke_softirq();
...... ......
- }
这个函数是由do_irq调用的,也就是中断返回时,软中断的调用点。只有在in_interrupt()返回为假且有pending的软中断时,才会调用软中断。
看in_interrupt的实现。
- #define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
- | NMI_MASK))
- #define in_interrupt() (irq_count())
而在__do_softirq增加了preempt_count软中断部分的计数,这样就避免了在运行软中断处理函数时,发生了硬中断从而再次调用软中断的问题。
其实在软中断函数do_softirq的入口也有类似的判断
- asmlinkage void do_softirq(void)
- {
- __u32 pending;
- unsigned long flags;
- if (in_interrupt())
- return;
- ...... ......
- }
同样是通过调用in_interrupt()来检查,来保证同一CPU上只有一个软中断运行实例。
通过上面的代码,我们知道了Linux kernel如何保证同一CPU上只有一个软中断的运行实例,同时也就明白了不同CPU为什么可以有同一类型的软中断处理函数同时运行——因为preempt_count是一个进程的值,而不同CPU上是不同的进程在运行。
阅读(1040) | 评论(0) | 转发(0) |