详解Linux中断处理中的hardirq与softirq机制
发布时间:2016-10-30 00:19:24 所属栏目:交互 来源:站长网
导读:今天在ChinaUnix论坛内核源码版上与linuxfellow网友讨论到hardirq和softirq的问题,虽然在《深入Linux设备驱动程序内核机制》(以下简称“ILDD”)第5章“中断处理”对此已有详细的解读,但是我觉得还是有必要再花点时间深入探讨一下这两者的区别。因为此前
今天在ChinaUnix论坛内核源码版上与linuxfellow网友讨论到hardirq和softirq的问题,虽
然在《深入Linux设备驱动程序内核机制》(以下简称“ILDD”)第5章“中断处理”对此已有详细的解读,但是我觉得还是有必要再花点时间深入探讨一
下这两者的区别。因为此前关于ARM上的中断处理我已经在另一篇帖子解密ARM based Linux内核中断处理框架 中讨论过,所以下面的讨论只限于x86 32位系统。 首先给出一个ILDD书中的一个插图,关于中断处理的整体框架: ![]() (图1) 接下来的一个插图显示了内核用于标识中断上下文(in_interrupt())的变量preempt_count的布局: ![]() (图2) 按照x86处理器在外部中断发生时的硬件逻辑,在do_IRQ被调用时,处理器已经屏蔽了对外部中断的响应。在图中我们看 到中断的处理大体上被分成两部分HARDIRQ和SOFTIRQ,对应到代码层面,do_IRQ()中调用irq_enter函数可以看做hardirq 部分的开始,而irq_exit函数的调用则标志着softirq部分的开始:
irq_enter()函数的核心调用是__irq_enter(),后者的主要作用是在图2的 preempt_count变量的HARDIRQ部分+1,即标识一个hardirq的上下文,所以可以认为do_IRQ()调用irq_enter函数 意味着中断处理进入hardirq阶段。此时处理器响应外部中断的能力依然是被disable掉的(EFLAG.IF=0),因为ISR基本上属于设备驱 动程序涉足的领域,内核无法保证在设备驱动程序的ISR中会否将EFLAG.IF置1(此处涉及可能的中断嵌套以及中断栈溢出问题,可以参考ARM中断处 理的那个帖子),所以我们会在内核代码中看到内核开发者为了尽可能避免非受控的ISR部分给系统带来的损害所做的努力。按照现在内核的设计理念,在 hardirq部分最好不要打开中断,所以处在hardirq上下文中的设备驱动程序的ISR应该尽可能快地返回(所谓只完成最关键的任务),而将耗时的 中断处理善后工作留到softirq部分,因为在softirq部分,内核会使EFLAG.IF=1,所以也意味着softirq部分可以随时被外部中断 所打断。 下面我们重点讨论一下softirq部分的实现原理,do_IRQ()中调用irq_exit函数标志softirq部分 的开始。 irq_exit()函数会首先在图2的preempt_count变量的HARDIRQ部分-1,目的是清除hardirq的上下文标记。然后它有个关键的调用invoke_softirq,用于实际的softirq处理工作:
第一个条件,主要用来防止softirq部分的重入,因为一旦有pending的softirq需要处理,那么invoke_softirq()的调用 (实际的工作发生在__do_softirq函数中)首先会将图2中SOFTIRQ部分+1,这样若在当前正在处理softirq过程中发生了外部中 断,hardirq部分标识了一个pending softirq,那么在irq_exit函数中将直接返回,而不会调用到invoke_softirq。 softirq部分的核心代码段如下:
对每个类型的softirq的处理发生在上面的do...while...循环中,原理其实非常简单,为节省文字,用下面一个草图来做说明(图3): ![]() 所以do...while...循环实际上是从bit 0遍历__softirq_pending变量,目前该变量的0~9分别对应10个不同类型的softirq,每个softirq对应不同的处理函数,比如HI_SOFTIRQ对应的action为tasklet_hi_action,它与TASKLET_SOFTIRQ的action的原理完全一样,也就是我们平常所说的tasklet。__softirq_pending是个per-CPU型的变量,因为SMP系统中每个处理器都可以独立处理各自到来 的外部中断,也都对应有各自的hardirq栈和softirq栈,详见Linux内核中的中断栈与内核栈的补充说明一贴。另外,在前面的帖子中我们一直说hardirq部分标识一个softirq,何谓标识一个softirq?其实就是调用tasklet_schedule()来把TASKLET_SOFTIRQ位置1. 在ILDD一书中实际上将tasklet分成两部分,分别放在第5章”中断处理“和第6章”延迟操作“,第5章侧重讨论softirq的机制,而第6章则重点讨论tasklet。 (原帖首发:http://www.embexperts.com/forum.php/forum.php?mod=viewthread&tid=543) (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |