在linux里,中断处理分为顶半(top half),底半(bottom half),在顶半里处理优先级比较高的事情,要求占用中断时间尽量的短,在处理完成后,就激活底半,有底半处理其余任务。底半的处理方式主要有soft_irq, tasklet, workqueue三种,他们在使用方式和适用情况上各有不同。soft_irq用在对底半执行时间要求比较紧急或者非常重要的场合,主要为一些subsystem用,一般driver基本上用不上。 tasklet和work queue在普通的driver里用的相对较多,主要区别是tasklet是在中断上下文执行,而work queue是在process上下文,因此可以执行可能sleep的操作。
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id) ;
request_threaded_irq() 是Linux kernel 2.6.30 之后新加的irq handler API,Linux kernel config 需要定义CONFIG_GENERIC_HARDIQS,kernel config 才有支援threaded irq 。
优点:
1 减少 kernel 延迟时间
2 避免处理中断时要分辨是在硬体中断或软体中断?
3 更容易为kernel 中断处理除错,可能可完全取代tasklet
原本的中断处理分上半部(硬体中断处理,必须关闭中断无法处理新的中断)跟下半部(软体中断处理),因此上半部的硬体中断处理必须尽可能简短,让系统反应速度更快。
request_threaded_irq 是在将上半部的硬件中断处理缩短为只确定硬体中断来自我们要处理的装置,唤醒kernel thread 执行后续中断任务。
分析request_threaded_irq()函数中的各个参数
1 irq:表示申请的中断号
2 handler:表示中断服务例程
3 thread_fn:中断线程化,此处传递的是NULL。NULL表示没有中断线程化。
此参数是最新版本中才出现的。为什么要提出中断线程化?
在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍有实时性保证。but,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当被线程化。
4 irqflags:表示中断标志位。
5 devname:表示请求中断的设备的名称。
6 dev_id: 对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。 共享中断时所用。