Kernel之中断处理底半部机制

[TOC]

主要记录一些整体的概念、框架和简单介绍,不涉及具体的原理和实现细节

背景

查看系统相关中断:

cat /proc/interrupts

中断服务程序要求尽量短小精悍,耗时短。但现实情况是中断到来时,需要完成的工作会比较多,需要进行较大量的耗时处理。于是Linux将中断处理程序分成了2部分:顶半部(Top Half)和底半部(Bottom Half)。但并不一定要分成2个部分, 本来中断要处理的工作比较少,则完全没必要底半部,只需要顶半部就足够了。

顶半部主要用于处理一些尽量少的比较紧急的东西,比如紧急的硬件操作,清除中断标志,记录相应中断信息供底半部使用。
底半部主要处理中断需要处理的绝大部分工作(比较耗时)。可以被新的中断打断,通常顶半部是不可被中断的。

所以这里主要介绍下底半部相关的一些机制:
Linux实现中断底半部的机制主要有tasklet、工作队列(work queue)、软中断(softirq)、中断线程化(threaded_irq)

tasklet:

执行上下文为软中断,执行时机通常是中断顶半部返回时。不允许睡眠。执行快, 短时期, 并且在原子态
主要相关使用伪代码:

/* 定义及关联 */
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);

/* 中断处理底半部 */
void xxx_do_tasklet(unsigned long)
{
	...
}

/* 中断处理顶半部, 中断申请时注册的中断处理回调函数*/
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
	...
	tasklet_schedule(&xxx_tasklet);
	...
}

工作队列:

执行上下文为内核线程,可以调度和睡眠。 具体可见:《Kernel之工作队列》
伪代码:

原理:https://zhuanlan.zhihu.com/p/94561631

软中断:

softirq, 不宜直接使用。tasklet是基于软中断实现。不允许睡眠。
细节可以参考: https://chasinglulu.github.io/2019/07/16/%E4%B8%AD%E6%96%AD%E5%BB%B6%E8%BF%9F%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6%E3%80%8Cinterrupt-delay-processing%E3%80%8D/

中断线程化(threaded_irq):

threaded irq handler所在的进程(内核线程)的调度类别是SCHED_FIFO,即属于实时进程
相关代码:

int __must_check
request_threaded_irq(unsigned int irq, irq_handler_t handler,
		     irq_handler_t thread_fn,
		     unsigned long flags, const char *name, void *dev);

int __must_check
devm_request_threaded_irq(struct device *dev, unsigned int irq,
			  irq_handler_t handler, irq_handler_t thread_fn,
			  unsigned long irqflags, const char *devname,
			  void *dev_id);

devm_开头的API申请的是内核管理(“managed”)的资源,一般不需要在出错处理和remove()里再显式释放资源,有点像JAVA的GC机制

参考

中断子系统: http://www.wowotech.net/sort/irq_subsystem

工作队列:http://www.wowotech.net/irq_subsystem/workqueue.html