软中断的实现原理及使用
软中断的实现原理及使用 主讲: 张琰 主要内容 下半部概述 软中断 Tasklet 工作队列 下半部机制的选择 下半部之间的同步 下半部概述 为什么叫下半部? 下半部是针对中断处理流程而言,下半部的任务就是执行与中断处理密切相关但中断处理程序本身不执行的工作。 中断处理的局限性 异步触发,可随时打断其他代码的执行 执行中断处理程序时,最好的情况下也会锁定当时中断线,最坏的情况是禁止所有本地中断。 往往对硬件进行操作,所以时限要求高 不在进程上下文件中运行,不能阻塞 下半部概述 下半部的引入 中断处理程序(上半部):快速、异步、简单的对硬件做出响应,完成那些对时间要求很严格的操作。 下半部:其他对时间要求相对宽松的任务。 下半部的工作 理想情况下,最好所有的工作都由下半部完成,因为中断处理程序中完成的工作越少越好,越快越好,这样断程序可以尽可能快的返回。 现实情况:中断处理程序响应中断,对中断的到达进行确认或其他一些对时间要求很严格的工作;其他全部由下半部完成。 下半部概述 上半部和下半部的工作划分 对时间非常敏感的任务在中断处理程序中执行 任务与硬件相关,在中断处理程序中执行 任务要保证不被其他中断(特别是相同中断)打断,在中断处理程序中执行 除以上所述以外的所有任务,在下半部中执行 下半部的实现机制 软中断(Softirq) Tasklet 工作队列(Work queues) 软中断(Softirq) 软中断的实现 软中断是在编译期间静态分配的 软中断由softirq_action结构表示,它在中定义。 static struct softirq_action softirq_vec[32]定义了软中断数组,每个被注册的软中断都占据该数据的一项。kernel/softirq.c 一个软中断不会抢占另一个软中断,唯一可抢占软中断的是中断处理程序。但其他软中断(包括相同类型的软中断)可以在其他处理器上同时运行。 一个注册的软中断必须在被标记后才会执行,称之为触发软中断(raising the softirq)。 软中断(Softirq) 软中断的执行时机 处理完一个硬件中断以后,在irq_exit()调用。kernel/irq/handle.c 在ksoftirqd内核线程中。kernel/softirq.c 在显示检查和执行待处理的软中断的代码中,如网络子系统。 无论哪一种方式唤起软中断处理,软中断都要在do_softirq()中执行。 kernel/softirq.c 软中断(Softirq) 软中断的使用 软中断使用介绍 软中断是保留给系统中对时间要求最严格以及最重要的下半部使用的。 目前只有网络子系统和SCSI子系统直接使用软中断 内核定时器和tasklet都是建立在软中断上的 只有当对时间要求严格并能自己高效地完成加锁工作时,才推荐使用软中断 添加新的软中断 分配索引 通过在中定义的一个枚举类型来静态地声明软中断。 索引表示一种相对优先级,索引号小的软中断先执行。 建立新的软中断必须在此枚举类型中加入新的项,根据你所期望的优先级来决定加入的位置。 使用习惯:HI_SOFTIRQ做为第一项;TASKLET_SOFTIRQ做为最后一项; 添加新的软中断 注册软中断处理程序 调用open_softirq()注册软中断处理程序 open_softirq()三个参数的含义 软中断索引号 软中断处理函数 Data域存放的值 软中断处理程序的特点: 允许响应中断,但其本身不能休眠 其执行时,当前处理器的软中断被禁止,但其他处理器仍可执行,所以需要考虑多处理器情况下的同步。 其内部使用的全局变量也需要严格的锁保护 不可通过互斥的加锁方法来防止其自身的并发 添加新的软中断 触发软中断 通过raise_softirq()将软中断设置为挂起状态 raise_softirq()参数为软中断号 在触发软中断前禁止中断,触发后再恢复回原来的状态。 raise_softirq_irqoff() 当中断本来就已经被禁止时,用此函数将软中断置为挂起状态。 内核执行完中断处理程序以后,马上会调用do_softirq(),让软中断去完成中断处理程序未完成的工作。 Tasklet Tasklet的实现 Tasklet是由软中断实现的 Tasklet有两种软中断 HI_SOFTIRQ TASKLET_SOFTIRQ Tasklet结构在中定义 Tasklet处理程序 tasklet_action() tasklet_hi_action() Tasklet Tasklet的使用 初始化tasklet 静态定义: DECLARE_TASKLET