中断处理及下半部
由中断和异常的区别可知,中断处理程序以一部方式执行,并且他有可能会打断其他重要代码(甚至包括其他中断处理程序)的执行。因此为了避免被打断的代码停止时间过长,中断处理程序应该执行得越快越好。
中断处理程序不再进程上下文中运行,所以他们不能阻塞,所以他们有很高的的实现要求。操作系统个必须有一个快速、异步、简单的机制负责对硬件做出迅速响应并完成那些时间要求很请严格的操作。
因此,整个中断处理流程被分成了两个部分:第一个部分是中断处理程序,内核通过对他的异步执行完成对硬件中断的即时响应。第二部分是下半部。
下半部
下半部的任务就是执行与中断处理密切相关但中断处理程序本身不执行的工作。
下半部机制的实现
下半部实现机制通常有软中断,tasklet,工作队列等。
软中断
LInux通过软中断实现下半部机制。软中断是在编译期间静态分配的,在内核中其实就是一个叫做softirq_vec的数组,数组包含了32个元素类型为softirq_action的元素。数组下标就表示了对应的软中断的优先级。Linux重要前6个元素被有效地使用。
每个softirq_action包含两个关键字段:指向软中断函数的一个action指针和指向软中断函数需要的通用数据结构的data指针。在处理软中断的是后,其实就是调用softirq_action中的函数指针,这个函数就是相应的软中断函数,完成被推迟的工作。
内核如何知道当前有哪些软中断等待处理?
cpu中有一个关键的32位掩码描述挂起的软中断。什么叫挂起的软中断?当某个中断处理程序在完成对中断的即时响应后,将复杂的后半部工作交给软中断,让内核知道这个软中断需要被处理。因此他需要将这个软中断标记为挂起,后续,内核在某些时机就会检查有哪些软中断被挂起,然后调用softirq_action的函数。中断处理程序就是通过这个32位掩码来标记软中断的。
哪些时候会检查软中断并处理?
- 从一个硬件中断代码返回时。当do_irq()完成了I/O中断的处理时或调用irq_exit()宏时。
- 在ksoftirqd内核线程中。在Linux内核中,每个cpu都有自己的ksoftirqd内核线程来辅助处理软中断(和tasklet),每个ksoftirqd内核线程都运行ksoftirqd()函数,这个函数实际上是在循环执行一些任务。当内核线程被唤醒时,就会检查软中断掩码并在必要时调用do_softirq()。
- 那些显式检查和执行待处理的软中断的代码中,如网络字系统中
tasklet
tasklet是利用软中断实现的一种下半部机制。tasklet能被动态地注册或注销。tasklet是I/O驱动程序中实现下半部的首选方法。从上面的表格可以看出,tasklet其实就是某种软中断。表中可以看到HI_SOFTIRQ和TASKLET_SOFTIRQ的软中断就是用于tasklet的。几个tasklet可以与同一个软中断相关联,每个tasklet执行自己的函数。这两种软中断之间没有真正的区别,只不过do_softirq()先执行HI_SOFTIRQ的tasklet,后执行TASKLET_SOFTIRQ的tasklet。
tasklet由tasklet_struct结构表示,每个结构体单独代表一个tasklet。
结构体中的func成员是tasklet的处理程序(像软中断中的action一样),data是他的唯一参数。
参考文献
- LInux内核设计与实现
- 深入理解Linux内核
推荐博文
https://www.cnblogs.com/li-hao/archive/2012/01/12/2321084.html