注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

FY

Johnson 's Blog

 
 
 

日志

 
 

linux 2.4.0软中断处理  

2016-12-29 11:13:36|  分类: Linux内核 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Linux 2.4.0

某个外部中断通道产生了中断,进入到do_IRQ服务程序

0x20开始的外部中断,都是使用的【中断门】,所以一旦通过中断门进入中断服务do_IRQ时,CPU的中断响应机制就自动被关闭了。但如果是在多处理器SMP上,还是需要通过spin_lock来进行加锁。

通过PENDING的标志,将同一通道上多次产生的中断进行了串行化

对同一个CPU而言不允许中断服务嵌套,而对于不同的CPU则不允许并发地进入同一个中断服务程序。

在执行完串化handle_IRQ_event函数后,就会判断是否要进行软中断

进入do_softirq

软中断可以看成是一个中断服务的后半段,它可以在稍微宽松的环境下执行,即可以在开中断的情况下执行。所以do_softirq中,会打开中断: __sti()

每个CPU都有各自对应的irq_cpustat结构体,这里面有__local_irq_count__local_bh_count,

针对in_interrupt,就是要判断该CPU__local_irq_count加上__local_bh_count,要不等于0,否则就认为是“在中断服务中

__local_irq_count在进入handle_IRQ_event时被递增1,在退出时被递减1

__local_bh_count在进入do_softirq时被递增1,在退出时被递减1

do_softirq函数会判断是否“在中断服务中它既不允许在一个硬中断服务程序内部执行,也不允许在一个软中断服务程序内部执行。所以这要通过in_interrupt加以检测

asmlinkage void do_softirq()

{

int cpu = smp_processor_id();

__u32 active, mask;

 

if (in_interrupt())

return;

 

local_bh_disable();

 

local_irq_disable();

mask = softirq_mask(cpu);

active = softirq_active(cpu) & mask;

 

if (active) {

struct softirq_action *h;

 

restart:

/* Reset active bitmask before enabling irqs */

softirq_active(cpu) &= ~active;

 

local_irq_enable();

 

h = softirq_vec;

mask &= ~active;

 

              do {

                     if (active & 1)

                            h->action(h);

                     h++;

                     active >>= 1;

              } while (active);

 

              local_irq_disable();

 

              active = softirq_active(cpu);

              if ((active &= mask) != 0)

                     goto retry;

       }

local_bh_enable();

        

因为在执行do_softirq中时,是开启中断的,所以有可能发生这样的情况:

外部中断0x20发生了,进入do_IRQ->handle_IRQ_event(处理完硬中断)->do_softirq(处理软中断),由于开启了中断,所以此时正好另一个外部中断0x30发生了,进入do_IRQ->handle_IRQ_event(处理完硬中断)->do_softirq(处理软中断),在这个do_softirq中,判断in_interrupt成功,表明在这之前我们已经在do_softirq中了,所以立马退出,这样就防止软中断嵌套执行。外部中断0x30它的硬中断服务程序是跑完了,但它的软中断没有被执行,

那它的软中断怎么办?我们继续,在0x30的软中断被立马退出后,接着就是0x30整个中断的IRET了,它返回到之前0x20的软中断中。我们看到,在do_softirq中,临时开启中断和关闭中断只有在do-while循环中,那现在我们0x30 中断返回肯定也是返回到这个do-while中,接着do-while循环执行完了后,会继续去判断当前CPU是否还有要处理的软中断

active = softirq_active(cpu); 如果有,则回到restart继续。这样一来,软中断被串行化了。

我们再细化一下

情况1

假设外部中断0x20先产生,进入它的硬中断服务程序,但是可能这个服务程序中是允许在开中断的情况下执行的,例如SA_INTERRUPT0.于是执行过程中另一个外部中断0x30产生了,进入它的do_IRQ,执行它的硬中断服务程序,它启动了某个软中断,执行完了硬中断后,准备执行0x30do_softirq,但是发现in_interrupt成功,为什么呢?是因为虽然我们退出了0x30的硬中断服务程序,但我们还没有退出0x20的服务程序,所以__local_irq_count总数不为0,又由于软中断服务不允许在一个硬中断服务程序内部执行,于是它直接退出,再进行0x30的中断返回,返回到0x20的硬中断服务程序中,当执行完0x20硬中断服务后,执行它的do_softirq,这时发现__local_irq_count==0了,已经完全不在一个硬中断服务程序中了,所以可以往下执行,这时的do_softirq会一起处理0x200x30造成的所有需要的软中断请求。这里可以看到do_softirq被串行化了。

情况2:

假设外部中断0x20先产生,进入它的硬中断服务程序,期间也没有再开启中断,于是0x20的硬中断服务完全被执行完了,然后进入它的do_softirq,由于软中断是比较宽松的,它会临时开启中断。于是在do-while的软中断处理中,另一个外部中断0x30产生了,进入0x30的硬中断服务程序,执行完了后,准备执行0x30do_softirq,但是发现__local_bh_count不为0,说明我们之前已经在某个do_softirq处理中了,于是立马退出,接着0x30进行中断返回,返回到0x20的软中断服务处理中,然后在执行完do-while后,再检查软中断请求,发现有新的软中断请求,这是由之前的0x30中断造成的软中断请求。于是我们在0x20do_softirq中再次restart,去处理这个软中断请求。

注:上面说的都是针对发生在同一个CPU的情况

也就是说,in_interrupt中判断使用的都是同一个CPUirq_cupstat结构体中的

__local_irq_count __local_bh_count

情况1代表了已经处在一个硬中断服务中,还未处理完的时候调用do_softirq的情景,情况2代表了已经do_softirq中,还未处理完,由于再次中断发生而造成的调用do_softirq的情景。不管是哪种情况,都不允许软中断的嵌套。都要进行串行化。

asmlinkage unsigned int do_IRQ(struct pt_regs regs)

{

       if (!action)

              goto out;

for (;;) {

              …….

              handle_IRQ_event(irq, &regs, action);

 

out:

       ……..

       if (softirq_active(cpu) & softirq_mask(cpu))

              do_softirq();

                   …..

在多处理器SMP上,如果CPU1号正在处理do_IRQ,此时CPU2号发生同一通道上的中断,则在do_IRQ中发现该通道上还是INPROGRESS状态,则只会设置PENDING标志位,而不会调用硬中断服务handle_IRQ_event.如此一来,多CPU上发生的硬中断也串行化了。

但在软中断处理do_softirq时,在判断是否在in_interrupt时,使用的是当前CPUirq_cpustat结构体中的__local_bh_count==0 来判断的,而CPU1号和CPU2号有它们各自的irq_cpustat结构体。所以有可能发生这种

情况3

CPU1上发生外部中断0x20,处理硬中断,然后进入do_softirq,此时发生了同一个外部中断,且发生在CPU2上,则处理硬中断,然后进入do_softirq,注意,此时是可以通过in_interrupt检查的,因为CPU2__local_bh_count ==0阿,所以CPU2号可以执行它自己的do_softirq

然后执行中断返回,返回到CPU1号,继续处理CPU1号的do_softirq。也就是说不同的CPU可以同时进入对软中断服务程序的执行。但不同的CPU不可以同时进入对硬中断服务程序的执行。

硬中断方面,使用中断处理结构体struct irq_est中的state,所有CPU都共享这个state,都要对这个state进行判断是否是INPROGRESS,从而达到不同CPU上的硬中断也是串行化的,不能嵌套。而软中断方面,使用的是各个CPU自己有struct irq_cpustat,所以它只能判断出自身当前CPU是不是已经处于一个软中断服务程序do_softirq中,但它管不了其他CPU,或者他看不到其他CPU是否也在执行do_softirq函数。所以多个CPU可以同时进入“它们各自的软中断处理中

  评论这张
 
阅读(5)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017