前言
本篇文章来讲解Linux系统对中断的处理,中断无论是在单片机还是在Linux中都是非常重要的那么这篇文章就来讲解一下Linux系统对中断的处理。
一、栈在中断中的作用
在中断处理过程中,栈起着重要的作用。栈是存储临时数据和函数调用信息的一种数据结构,在中断处理中,栈用于保存和恢复处理器的上下文信息,以及传递参数和返回地址等关键信息。
以下是栈在中断处理中的几个关键作用:
1.上下文保存:当中断事件发生时,处理器会中断当前正在执行的任务,然后立即转向中断服务程序(ISR)。为了保护当前任务的上下文不被破坏,处理器会将当前任务的寄存器状态、程序计数器(PC)等信息保存在栈中。这样,在中断处理完成后,可以从栈中恢复这些信息,继续执行被中断的任务。
2.中断处理程序的局部数据保存:中断处理程序通常需要使用一些局部变量和临时数据。这些数据可以保存在栈上,以便在中断处理中进行操作和存储。栈提供了一种方便的方式来管理这些数据,确保中断处理程序的临时数据不会干扰其他部分的执行。
3.传递参数:中断服务程序可能需要某些参数来处理中断事件。这些参数可以通过将它们压入栈中来传递给中断处理程序。中断服务程序可以通过栈来获取这些参数,并根据需要进行处理。
4.返回地址保存:在处理器启动中断服务程序之前,它会将中断服务程序的入口地址压入栈中作为返回地址。这样,在中断处理完成后,处理器能够从栈中弹出返回地址,并将控制权返回到中断发生之前的位置,继续执行被中断的任务。
二、Linux中的硬件中断和软件中断
在Linux中,硬件中断(Hardware Interrupt)和软件中断(Software Interrupt)是用于处理系统事件和异步请求的两种不同类型的中断。
1.硬件中断:
硬件中断是由计算机硬件设备(如网卡、键盘、鼠标等)发出的信号,用于通知处理器某个特定事件已发生,需要进行相应的处理。
当硬件设备发生中断时,它会向处理器发送一个中断请求(IRQ),处理器会立即中断当前正在执行的任务,并跳转到预定义的中断处理程序(Interrupt Service Routine,ISR)中去处理这个中断事件。
在Linux系统中,硬件中断的处理是通过使用中断控制器(Interrupt Controller)来实现的。中断控制器负责接收和分发硬件中断请求,将中断请求映射到相应的中断处理程序。
2.软件中断:
软件中断是由软件主动触发的中断事件,它是通过软件指令(如系统调用或软中断指令)产生的。
软件中断通常用于系统内核与用户空间的交互、系统调度、异常处理、定时器事件等。
软件中断是通过在内核空间中执行特定的代码来处理的,这些代码被称为中断处理程序或中断服务例程(Interrupt Service Routine,ISR)或系统调用处理程序。
软件中断通常使用特定的中断向量或中断号来标识不同的中断事件。当一个软件中断被触发时,处理器会从当前执行的指令切换到相应的中断处理程序,处理完中断后再返回到原来的指令继续执行。
硬件中断和软件中断都是为了处理异步的事件和请求而设计的,它们允许处理器在遇到事件发生时能够及时地响应,提高了系统的实时性和并发性。在Linux系统中,硬件中断和软件中断共同工作,处理各种系统事件、设备请求和用户程序的需求,保证了系统的正常运行和高效性能。
三、中断处理原则
1.不能嵌套
在MCU中中断都是可以嵌套的,但是在Linux中是不支持中断的嵌套的,当执行中断程序时需要将数据和各种寄存器的值保存到栈中,栈的大小不是无限的,当中断不断的嵌套时就可能会发生爆栈
导致系统崩溃,所以在Linux中直接禁止了中断嵌套。
2.越快越好
在中断处理过程中CPU是无法进行调度的,假如中断执行的时间非常长,那么将导致系统卡死,所以中断的处理越快越好。
四、中断的上半部和下半部
在Linux中,中断处理可以分为上半部(Top Half)和下半部(Bottom Half),用于异步事件的处理和延迟处理。
1.上半部(Top Half):
上半部是中断处理的第一阶段,也称为中断服务例程(ISR,Interrupt Service Routine)。它是在中断事件发生后,立即运行的处理程序。
上半部通常负责执行关键的、时间敏感的处理操作,需要尽快完成。这可能包括保存关键数据、更新硬件状态、响应设备、处理紧急任务等。
上半部需要尽量快速地执行完毕,以确保及时响应其他中断事件和保持系统的实时性。因此,上半部通常采用较短的执行路径和简单的操作。
下半部(Bottom Half):
下半部是中断处理的第二阶段,也称为延迟处理或后半部(Deferred processing)。它是在中断处理的延迟情况下执行的处理程序。
下半部通常负责执行相对较慢、复杂或可能阻塞的操作,如长时间的计算、I/O操作、内存分配等。
下半部的触发可以有多种方式,例如软中断、任务队列、工作队列等。这些机制允许在适当的时机,将需要处理的任务推迟到稍后执行,以避免在中断上下文中执行耗时操作和阻塞。
上半部和下半部的划分可以使中断处理过程更加高效和灵活。上半部负责进行及时的关键处理,尽量缩短中断响应时间,而下半部则负责较为复杂和耗时的处理任务,通过延迟执行来降低对实时性的影响。
五、中断的处理流程
1.执行中断的上半部,此时其他中断无法打断当前中断的执行。
2.开中断允许其他中断的执行,执行中断下半部。
3.执行完中断下半部,关中断,将控制权返回给之前的程序。
注意:
1.在中断下半部执行的过程中可以被这个中断程序打断,再次执行中断上半部,也就是说中断上半部和下半部执行次数是N:1。
2.中断上半部执行完后会执行全部的中断下半部的程序。
3.中断的上半部和下半部不能休眠,休眠后将无法进行调度。
六、中断下半部要执行耗时任务该怎么解决
在中断下半部虽然开启了中断,期间可以处理其他中断,但是在中断执行的过程中,APP还是无法执行的,那么这就会导致应用程序卡死了,所以处理耗时的中断需要使用内核线程,使用内核线程可以保证中断下半部的执行和APP的执行可以进行调度,从而不会导致APP的卡死。
1.任务队列tasklet
任务队列是一种中断下半部的机制,用于延迟处理和执行与中断相关的工作。
任务队列可以看作是由一个或多个回调函数组成的队列,这些回调函数会在中断处理程序执行完毕后被异步调度执行。
每个任务队列都有一个优先级,高优先级的任务队列在任务队列调度时会优先执行。
任务队列具有自动禁止中断和解禁中断的机制,以确保在执行任务队列期间不会被同一中断再次触发。
任务队列可以在不同的上下文中执行,包括软中断上下文、进程上下文和内核线程上下文。
2.工作队列
工作队列:
工作队列是一种机制,用于在中断上下文之外异步执行一些工作,以避免在中断处理程序中执行耗时的操作。
当中断发生时,可以将需要延迟处理的任务添加到工作队列中,而不是立即在中断上下文中执行这些任务。
工作队列将任务放入内核的工作队列队列中,然后由内核调度机制在适当的时机(例如系统空闲时)执行这些延迟处理的任务。
工作队列的执行在进程上下文中进行,允许执行复杂的操作、I/O访问和内存分配等,而不会对实时性产生太大影响。
3.threaded irq
Threaded IRQ是一种功能强大的中断处理机制,它允许将中断处理程序作为一个内核线程来执行,而不是在中断上下文中运行。
当中断发生时,Threaded IRQ会触发一个内核线程来处理中断,而不是在中断上下文中直接执行中断处理程序。
线程化中断可以让中断处理程序运行在进程上下文中,拥有完整的内核环境,可以执行复杂的操作、调用内核API,以及进行同步和互斥等操作。
线程化中断可以提高系统的可靠性和可维护性,因为它可以将中断处理程序与其他内核线程隔离开来,同时还可以减少中断处理程序的复杂性。
总结
本篇文章就讲解到这里,下篇文章继续讲解Linux中的中断处理。