bottom half
本帖最后由 _nosay 于 2016-11-02 17:17 编辑http://bbs.chinaunix.net/thread-4255596-1-1.html(续)
[*]bottom half 粗略理解
简单的说,就是将一件完整的事细化,想象一下,如果有个人在食堂窗口打完饭之后,非要吃完再走,导致后面的人都得排队等着,是不是很憋屈?所以食堂里划分了打饭区和用餐区。
对于计算机来说,如果设计不合理就会导致更严重的后果,比如网络中一个报文经历了重重“磨难”,从发送端到达接收端,却因为接收端关中断而必须重传,大大增加了网络负担。
[*]关中断=可以保护,开不断≠不需要保护
将比较耗时的处理部分放在开中断时执行,纯粹是为了执行它的时候,CPU仍然能够响应中断,并不代表这段过程允许受到干扰,比如Linux内核为了减轻驱动程序员编写中断处理函数的负担,对于bottom half设计的就很保守,用两"把"锁保护bh函数的执行不被干扰:
① bh函数执行途中,当前CPU又产生一次同样的中断,最终又进入该函数执行,所以每个CPU内部有一把锁;
② bh函数执行途中,其它CPU又产生一次同样的中断,最终又进入该函数执行,所以所有CPU公共有一把锁。
除了用锁,还可以像do_IRQ()函数那样用IRQ_INPROGRESS、IRQ_PENDING标记,对某个执行过程进行保护,所以千万不要在“中断的开关”与“保护”之间完全画等号。
(内核很多对于同一个问题的不同解决方案,有时候没有明显的好坏之分,好的内核或驱动程序员,应该根据自己的应用场景,尽量选择合适的机制,让整个系统能更好的运行)
[*]软中断由来
上述提到bottom half缓解了中断丢失的问题,但对bh函数的保护做的过于保守,而软中断是基于对保守程度的放开,设计的一种新框架,并且为了兼容老的bh函数(依赖于老框架的充分保护),即保留bottom half机制,也就是在softirq机制的基础上再多加一些保护罢了。
(学内核时深刻体会到一种感觉:永无止境。经常当感觉这样已经很好了的时候,新版本的内核又设计出更精妙或更完善的方案,所以说学习内核可以治心浮气躁,让心静下来{:qq28:})
[*]softirq过程
① 初始化
softirq_init()函数用于整个软中断框架的初始化(只初始化了两种软中断:HI_SOFTIRQ、TASKLET_SOFTIRQ,其它用于以后扩展,以及基于HI_SOFTIRQ软中断的bottom half框架初始化);
将来某些内核子模块需要使用某种软中断时,该子模块初始化时需要调用相应接口,注册软中断函数,比如init_bh()。
② 软中断的产生及响应
软中断与硬中断最根本的区别,就是执行真正中断服务函数的时机不同,“软中断服务函数”并不是在硬件产生中断时CPU自动跳转到的那段代码内直接执行,为了事后知道刚才产生了哪种中断,需要“标记”下来(对于软中断来说,就是“产生”)。
(这应该就是“软中断”这个名字的由来,一方面硬中断的产生是通过硬件上的INTR引线获知,而软中断是通过软件中的变量获知,另一方面相对于硬中断处理函数,它的时间要求更“缓和”、硬件要求也更“缓和”(不要求关中断))
如同文件系统中,每个文件对应的dentry只有一个,但多个进程或同一进程,可以有多个file结构表示对该文件的操作上下文。软中断框架中softirq_vec、bh_task_vec、bh_base等在整个内存中只有一份,但每个CPU的“软中断状态信息”,各自独自占有一份(所以softirq相对于bottom half,就解放了所有CPU之间的那把锁,而加上更严格的限制,就可以兼容bottom half):
关键是__softirq_active、__local_irq_mask,它们都占32位,当它们第x位都为1时,执行softirq_vec.action()函数,通过上面的open_softirq()函数可以看出,在打开HI_SOFTIRQ、TASKLET_SOFTIRQ“软中断通道”的同时,也将各个CPU的mask相应位也打开了。
而tasklet_hi_vec是各个CPU希望通过软中断框架最终执行的函数,即刚刚“标记”并挂到链表的函数,比如将__localirq_active的第0位打开,是希望通过softirq_vec.action()指向的tasklet_hi_action()函数,从softirq框架“过渡”到bottom half框架,那里就会用到该CPU对应的tasklet_hi_vec[].list,依次执行“产生”中断时,挂在上面的hb函数:
另外,什么时候“产生”中断?什么时候响应中断?
硬件产生时钟中断时,执行do_timer(),里面只是“产生”一下软中断,很快就返回了:
每次硬中断执行完处理函数,或从系统调用返回时,会判断是否需要执行软中断处理函数:
③ HI_SOFTIRQ、TASKLET_SOFTIRQ软中断比
HI_SOFTIRQ软中断最终要执行的,通过bh_task_vec挂到链表里的bh函数链,由tasklet_hi_action()→bh_action()函数“包装”,外面加了锁;
TASKLET_SOFTIRQ软中断最终要执行的,也是通过bh_task_vec挂到链表里,由tasklet_action()函数“包装”,外面没有加锁。
所以,如果某个软中断服务函数,可以多CPU并行执行,但必须要求硬件关中断,就可以注册为TASKLET_SOFTIRQ。
[*]三个很相似的概念
① 硬中断:外部设备对CPU的中断
② 软中断:“硬中断服务程序”对内核的中断
③ 信号:内核(或其它进程)对某个进程的中断(详见《Linux内核源代码情景分析》6.8节)
(概念不是用来咬文嚼字的,是用来更简单的表达和更方便理解,所以思想的传播需要概念,你如果正在抱怨概念,那肯定是在抱怨自己不肯努力去理解它们{:qq28:})
页:
[1]