本文主要的议题是作为一个普通的驱动工程师,在撰写本身卖力的驱动的时候,如何向Linux Kernel中的中断子系统注册中断措置惩罚惩罚函数?为了理解注册中断的接口,必需了解一些中断线程化(threaded interrupt handler)的根本常识,这些在第二章描述。第三章主要描述了驱动申请 interrupt line接口API request_threaded_irq的规格。第四章是进入request_threaded_irq的实现细节,分析整个代码的执行过程。
二、和中断相关的linux实时性分析以及中断线程化的配景介绍
1、非抢占式linux内核的实时性
在遥远的过去,linux2.4之前的内核是不撑持抢占特性的,具体可以参考下图:
工作的开始源自高优先级任务(橘色block)由于要期待外部事件(例如网络数据)而进入睡眠,调理器调理了某个低优先级的任务(紫色block)执行。该低优先级任务欢畅的执行,直到触发了一次系统挪用(例如通过read()文件接口读取磁盘上的文件等)而进入了内核态。仍然是熟悉的配方,仍然是熟悉的味道,低优先级任务正在执行不会变革,只不过从user space切换到了kernel space。外部事件总是在你不想让它来的时候到来,T0时刻,高优先级任务期待的阿谁中断事件产生了。
中断虽然产生了,但软件不必然立刻响应,可能由于在内核态执行的某些操纵不但愿被外部事件打断而主动*了中断(或是*了CPU的中断,或者MASK了该IRQ number),这时候,中断信号没有立刻得到响应,软件仍然在内核态执行低优先级任务系统挪用的代码。在T1时刻,内核态代码由于退出临界区而打开中断(注意:上图中的比例是不协调的,一般而言,linux kernel不会有那么长的关中断时间,上面主要是为了暗示清楚,同理,从中断触发到具体中断处事措施的执行也没有那么长,都是为了表述清楚),中断一旦打开,立刻跳转到了异常向量地点,interrupt handler抢占了低优先级任务的执行,进入中断上下文(虽然这时候的current task是低优先级任务,但是中断上下文和它没有任何关系)。
从CPU开始措置惩罚惩罚中断到具体中断处事措施被执行还需要一个分发的过程。这个期间系统要做的主要操纵包孕确定HW interrupt ID,确定IRQ Number,ack或者mask中断,挪用中断处事措施等。T0到T2之间的delay被称为中断延迟(Interrupt Latency),主要包孕两部分,一部分是HW造成的delay(硬件的中断系统识别外部的中断事件并signal到CPU),此外一部分是软件原因(内核代码中由于要掩护临界区而*中断引起的)。
该中断的处事措施执行完毕(在其执行过程中,T3时刻,会唤醒高优先级任务,让它从sleep状态进入runable状态),返回低优先级任务的系统挪用现场,这时候并不存在一个抢占点,低优先级任务要完成系统挪用之后,在返回用户空间的时候才呈现抢占点。漫长的期待之后,T4时刻,调理器调理高优先级任务执行。有一个术语叫做任务响应时间(Task Response Time)用来描述T3到T4之间的delay。
2、抢占式linux内核的实时性
2.6内核和2.4内核显著的差别是供给了一个CONFIG_PREEMPT的选项,打开该选项后,linux kernel就撑持了内核代码的抢占(固然不能在临界区),其行为如下:
T0到T3的操纵都是和上一节的描述一样的,差此外处所是在T4。对付2.4内核,只有返回用户空间的时候才有抢占点呈现,但是对付抢占式内核而言,即等于从中断上下文返回内核空间的进程上下文,只要内核代码不在临界区内,就可以产生调理,让最高优先级的任务调理执行。
在非抢占式linux内核中,一个任务的内核态是不成以被其他进程抢占的。这里并不是说kernel space不成以被抢占,只是说进程通过系统挪用陷入到内核的时候,不成以被其他的进程抢占。实际上,中断上下文固然可以抢占进程上下文(无论是内核态还是用户态),更进一步,中断上下文是拥有登峰造极的权限,它甚至可以抢占其他的中断上下文。引入抢占式内核后,系统的平均任务响应时间会缩短,但是,实时性更存眷的是:无论在任何的负载情况下,任务响应时间是确定的。因此,更需要存眷的是worst-case的任务响应时间。这里有两个因素会影响worst case latency:
(1)为了同步,内核中总有些代码需要持有自旋锁资源,或者显式的挪用preempt_disable来禁止抢占,这时候不允许抢占
(2)中断上下文(并非只是中断handler,还包孕softirq、timer、tasklet)总是可以抢占进程上下文