一 Linux中断原理
Linux中断(Interrupt)是指在计算机执行过程中,由于某些事件发生(例如硬件请求、错误、异常等),CPU暂停当前正在执行的程序,转而执行相应的处理程序的过程。中断是计算机多任务环境下的一种重要机制,它可以保证不同任务之间的公平访问 CPU 时间,以及及时响应外部事件。
中断提供了一种及时响应硬件故障和外部事件的方式,从而确保系统能够及时处理这些事件并保持正常运行。在Linux系统中,中断被广泛应用,从底层的驱动程序到高层的分布式系统,中断都扮演着重要的角色。
1 Linux中断的调度方式
在Linux系统中,中断的调度方式有以下几种:
1.硬件调度:当一个中断被触发时,硬件会自动将该中断的上下文信息保存到栈中,并将处理器的状态切换到内核态。然后硬件会发送一个目标中断,通知内核处理该中断。
2.软件调度:在内核中,中断可以通过注册的中断处理函数进行处理。当一个中断被触发时,内核会查找对应的中断处理函数,并调用该函数进行处理。
3.嵌套调度:当一个中断被触发时,内核会保存该处理器的状态并切换到内核态。如果该中断处理函数需要较长的时间才能完成,那么它可能会被更高优先级的中断打断。此时,内核会将高优先级的中断保存到栈中,并在处理完当前中断后再处理高优先级的中断。
2 使用中断解决问题
Linux中断可以用来解决许多硬件和软件问题,例如:
1.实时性应用:通过源中断及时响应外部事件,保证系统能够及时处理并保持正常运行。
2.I/O操作:通过源中断完成数据传输和读取,提高系统的I/O性能。
3.并发处理:通过多线程或多进程实现并发处理,提高系统的吞吐量和响应速度。
4.系统调优:通过调整中断的优先级和掩码来解决中断冲突问题,优化系统的性能和稳定性
3 中断分类
根据中断触发来源
- 机器故障中断(Machine check interrupt):当计算机系统发生硬件错误时,比如内存错误、缓存错误等,会触发机器故障中断。
- I/O中断(I/O interrupt):当计算机与外部设备进行交互时,比如打印机、键盘、显示器等,会触发I/O中断。
- 外部中断(External interrupt):来自计算机系统外部装置的中断,比如门铃、电话、键盘等。
- 中断控制器中断(Interrupt controller interrupt):中断控制器负责管理计算机系统中的中断,当需要切换中断优先级或处理中断时,会触发中断控制器中断。
- 定时器中断(Timer interrupt):计算机系统中常常使用定时器来产生定时中断,比如系统时钟、计时器等。
- 软件中断(Software interrupt):软件中断是由程序员故意引起的一类中断,通常用来实现系统调用或异常处理等。
概括为 硬中断、软中断
根据屏蔽类型
NMI中断,不可屏蔽中断,产生这个中断的时候,表示系统发生了致命的错误。
INTR可屏蔽中断。
NMI 如 watchdog 调试、跨 PE 同步和热补丁 ’操作系统依赖中断来支持性能分析
RAS事件处理
后者的INTR其中就包含了我们的FIQ、IRQ。中断定义宏都会带上INTR。
4 中断流程
- 保存上下文:在处理中断之前,需要先把当前执行的任务的寄存器状态(包括CPU寄存器和程序计数器等)保存到内核栈上。
- 查找中断向量表:根据接收到的中断信号类型,在中断向量表中查找相应的处理函数。
- 执行处理函数:执行对应的中断处理函数,对中断进行处理。
- 恢复上下文:执行完中断处理函数后,需要把之前保存的上下文恢复到原来的任务中,让程序继续执行。
在Linux系统中,中断处理程序通常由内核编写和实现,外设通常会使用中断机制与CPU进行通信,以请求处理或传递数据。中断处理程序可以看作是一种特殊的系统调用,它由硬件触发,但不同于用户进程的系统调用,它是由硬件或软件引发的紧急事件,要求CPU尽快停止当前工作,转而执行相应的处理程序。
5 中断处理 及优先级
在Linux系统中,中断处理涉及到两个概念:中断优先级和中断响应次序。其中,中断优先级是指各个中断源在中断请求和服务之间的优先级别;中断响应次序是指在中断请求和服务之间对于不同中断源的响应顺序。
中断优先级的设置通常涉及到一个优先级计数器或者优先级码,不同的中断源会有不同的优先级计数器或优先级码。当一个中断源发出中断请求时,系统会检查该中断源的优先级计数器或优先级码,如果它的值比其它中断源的高,那么它就会被优先响应。否则,系统会继续检查其它中断源的优先级计数器或优先级码,直到找到一个中断源被优先响应。
在Linux系统中,中断优先级的设置通常涉及到抢占优先级和响应优先级两个概念。抢占优先级决定了一个中断源能否抢占其它中断源的服务,而响应优先级则决定了一个中断源在等待服务时的优先级别。在STM32(Cortex-M3)中,每个中断源都需要被指定这两种优先级。
6 中断向量表
中断向量号是指计算机系统中的中断类型号(也称中断矢量号),每个中断类型都有一个对应的编号(或者向量),用于指示硬件或者操作系统在处理该中断时需要跳转到的地址。
在早期的微机系统中,中断向量号通常指的是硬件产生的中断入口地址或存放中断服务程序的首地址。例如,在Intel 8086微处理器中,每个中断类型都有一个16位的向量号,这些向量号被存储在中断向量表中,可以通过设置中断标志位来响应不同类型的中断。
在现代的计算机系统中,中断向量号通常由操作系统或者设备驱动程序动态分配,并通过中断向量表或者中断描述符表进行管理。这些表中存储了中断向量号、中断处理程序的地址以及其他相关信息,供硬件在处理中断时使用。
二 中断嵌套与同步
软中断可以抢占线程,硬中断可以抢占软中断也可以抢占线程,而返回来则不能抢占。
中断嵌套是中断技术中的一种非常重要的同步机制。所谓中断嵌套,是指当CPU执行某个中断服务程序时,如果收到更高级别的中断请求,CPU会立即暂停当前的中断服务程序,转而去处理新的更高级别的中断请求。等处理完新的中断请求后,CPU会重新回到原来的中断服务程序,从暂停的地方继续执行。
中断嵌套在操作系统中起着非常重要的作用,例如,当用户线程执行时,操作系统会通过中断机制来管理调度其他线程,实现多线程并发执行。在这种情况下,中断嵌套可以保证操作系统能够及时响应更高级别的中断请求,从而使整个系统的并发性能得到提升。
需要注意的是,不同类型的中断可能有不同的优先级,因此中断嵌套在实现时需要考虑优先级调度问题。在Linux内核中,如果驱动在申请注册中断时没有特别的指定,do_irq函数在处理中断时是开启中断的。如果在驱动的中断处理函数正在执行的过程中,出现同种类型的中断或者不同种类的中断,这时候新的中断会被立即处理。对于同种类型的中断,由于其使用同样的IDT表项,通过其状态标志(IRQ_PENDING和IRQ_INPROGRESS)可以防止同种类型中断函数的执行。对于不同种类的中断,则可以自由的嵌套。( linux下的不同类型硬中断处理是可以嵌套的)
中断线程和工作队列
中断里不宜调用会阻塞、休眠的函数,这对软中断函数的编程是很不利的,为此内核开发了两种方法,中断线程和工作队列。
threaded_irq 是一种内核支持的中断处理机制,用于在中断处理函数中处理重要紧急的任务,然后使用线程来处理耗时复杂的任务。它支持在中断处理函数中设置IRQF_ONESHOT标记,这样内核会自动帮助我们在中断上下文中屏蔽对应的中断号,而在内核调度线程执行后,重新使能该中断号。
workqueue 是内核中使用最广泛的线程化中断处理机制。系统中有一些默认的工作队列,你也可以创建自己的工作队列,工作队列背后对应的是内核线程。你可以创建一个work,然后push到某个工作队列,然后这个工作队列背后的内核线程就会去执行这些work。下面我们来看一下工作队列的接口。