一、什么是软中断?
内核中的软中断(Softirqs)和任务下半部(Tasklets)是Linux内核中用于在中断上下文之外处理中断服务的一种底层机制。这些机制解决了不能在中断服务例程(ISR)中执行耗时操作或者需要睡眠的操作的问题。软中断提供了一种在中断上下文中延迟处理的方法,允许中断处理分为两个阶段:顶半部和底半部。
顶半部(Top Half)
- 发生硬件中断时,首先会执行顶半部。
- 顶半部的代码通常运行在硬中断上下文,需要尽可能快地执行,因为在顶半部执行期间,相同的中断或其他中断可能被锁定,这会影响系统响应时间。
- 它通常负责快速执行与硬件交互的必要步骤,如读取寄存器或复位硬件中断状态,并且快速结束,以免长时间占用中断。
底半部(Bottom Half)
- 底半部是中断处理的延迟执行部分,用于执行更复杂或耗时的操作。
- 它在中断上下文之外执行,可以被其他中断打断。
- 底半部机制允许系统维持较高的响应性,因为顶半部可以快速释放中断线,让其他中断能够得到处理。
软中断(Softirqs)
- 软中断是Linux内核处理底半部工作的最原始的机制。
- 它们是静态定义的,数量固定,具体在<linux/interrupt.h>中定义。
- 每个CPU都有自己的软中断向量和状态。
- 软中断的处理是延迟的,常常是在中断返回后或者在其他处理器空闲时由内核调度器触发执行。
- 它们具有高性能,但开发起来相对复杂,因此Linux中还引入了更简化的底半部处理机制,即任务下半部(Tasklets)。
任务下半部(Tasklets)
- Tasklets是建立在软中断之上的一个简化的抽象,提供了更简单的接口。
- Tasklets可以动态创建,运行在软中断的上下文中,允许将小任务推迟到不会影响系统实时行为的时候执行。
- Tasklets可以被禁用和重新启用,但在设计上,同一个Tasklet在系统中的多个CPU之间不会并行执行。
软中断和任务下半部的处理通常发生在如下几个时间点:
1. 中断处理的硬中断返回后。
2. 当系统中断返回到用户空间前。
3. 内核检测到某个CPU运行在空闲循环(idle loop)时。
在多处理器系统中,软中断和任务下半部的处理需要考虑并发性和负载均衡,内核通常会在不同的CPU上分配这些任务,以充分利用系统资源。
二、软中断的实现
内核软中断(Softirqs)在Linux内核中是通过一系列底层机制实现的。下面是一个高层次的概述,展示了软中断是如何工作和实现的:
1. 内核数据结构定义:
- 软中断在内核中通过一个数据结构(通常是数组)来表示,其中每个条目代表一个软中断类型。Linux内核为每个处理器维护一个这样的数据结构。
- 在`<linux/interrupt.h>头文件中预定义了一组软中断类型,例如网络相关的 NET_TX_SOFTIRQ` 和 NET_RX_SOFTIRQ,以及调度器相关的 SCHED_SOFTIRQ 等。
2. 初始化:
- 在系统启动时,内核会初始化软中断机制,包括预定义软中断向量的初始化。
3. 中断处理和软中断激活:
- 当硬件中断发生并被服务时,顶半部(Top Half)快速执行,并且在必要时通过调用特定的函数例如 raise_softirq 激活一个或多个软中断。
- 激活软中断涉及到设置相应软中断的状态,通常是通过设置标志位来指示这个软中断需要被处理。
4. 软中断处理:
- 软中断处理可以在几种不同的上下文中执行。最常见的情形包括从中断上下文返回到用户态之前,以及内核检测到CPU空闲时。
- 当内核准备处理软中断时,它会检查每个软中断的状态,并对设置了激活标志的软中断调用其注册的处理函数。
- 这个处理函数是在软中断注册时指定的,是执行实际任务的代码,比如网络数据的接收和发送处理函数。
5. 并发和锁定:
- 由于软中断可以在多核系统中的任意CPU上执行,因此内核必须确保某一特定类型的软中断在同一时刻只能在一个CPU上运行。内核中实现了锁机制来管理这种并发。
- 为了保证性能和避免死锁,软中断的执行过程中一般不能进行阻塞操作。
6. 性能优化:
- 内核会尝试尽可能高效地处理软中断,包括可能的负载均衡(将软中断工作分配给不同的CPU)以及“延迟处理”(如ksoftirqd守护线程)来降低软中断对实时任务的影响。
7. ksoftirqd守护线程:
- 对于每个CPU,内核都维护了一个名为ksoftirqd的内核线程。这个线程负责确保软中断得到处理,特别是当系统很忙且软中断无法及时处理时。
- 这个线程的优先级很低,只有当系统的软中断负载较重时才会运行,以避免影响到更重要的任务。
综上所述,软中断是内核为了处理不适合在硬件中断上下文直接执行的任务而设计的一种轻量级机制。它们可以延迟执行并分担中断处理的负载,同时满足系统对实时性的需求。
三、内核抢占与软中断
Linux 内核自 2.6 版本开始,引入了主动抢占(Voluntary Preemption)和完全抢占(Preemptive Kernel)的概念,并且在随后的更新中继续提升了对抢占的支持。在 Linux 内核中,对抢占的支持可以通过内核配置选项进行调整。
有以下几种内核抢占模型:
1. 无抢占内核(No Preemption):这是传统的 Linux 内核模型,用于需要非常高稳定性和响应时间不是首要考虑的服务器环境。
2. 自愿抢占(Voluntary Preemption, CONFIG_PREEMPT_VOLUNTARY):这种模式在内核中插入许多显式的抢占点,以便提高系统的响应性。这种模式适合大多数台式机和笔记本电脑使用,因为它在系统响应性和稳定性之间提供了一个很好的折衷。
3. 抢占式内核(Preemptive Kernel, CONFIG_PREEMPT):这个选项是为了最大程度地降低内核代码的延迟,特别适合需要高响应性的桌面和嵌入式系统,但可能会牺牲一些稳定性。
4. 实时内核(Real-time Kernel, CONFIG_PREEMPT_RT):这是通过实时补丁(PREEMPT_RT)获得的 Linux 内核变种,可以为需要实时响应的系统提供预测性的、低延迟的行为。适用于工业、科研、音视频处理等对实时性要求很高的场合。
发行版维护者或用户可以根据自己的需求选择适当的抢占模式。
内核抢占(Kernel Preemption)
内核抢占是指操作系统允许一个内核模式的进程被另一个更高优先级的进程抢占。这通常发生在以下几种情况:
1. 当一个进程完成了它的时间片。
2. 当更高优先级的进程准备运行时,例如,从睡眠状态被唤醒。
3. 一些同步机制可能会导致当前运行的进程放弃处理器。
在没有抢占的内核中,一旦进程进入内核模式执行系统调用或其他内核任务,它会一直运行,直到主动放弃CPU控制权。这可能会导致系统响应变慢,因为高优先级任务可能需要等待低优先级任务完成其内核模式下的工作。内核抢占能够提高系统的响应性,特别是在多任务环境下。
软中断(Softirqs)
软中断是Linux内核中处理中断相关工作的一种机制。它们是相对硬件中断的概念(在旧一些的资料可能会碰到"硬中断"这一英文直译术语,但通常现在更倾向于直接使用英文"hardware interrupt");硬件中断是由CPU外部设备触发的,是中断处理的第一阶段。
当硬件中断发生时,CPU会立刻暂停当前执行的任务,转而执行一个非常短小的中断服务程序(Interrupt Service Routine, ISR),ISR的任务是快速地响应中断,执行一些紧急处理,然后标记软中断去完成剩余工作。这使得中断服务程序可以快速结束,CPU可以尽快恢复其他任务的执行。软中断处理则是延后执行的,可以批量处理一些工作,或者在处理器比较空闲的时候再执行。
通过将中断处理分为两个阶段,Linux内核能够提供快速响应硬件中断的同时,又能将耗时的处理工作推迟到软中断中去完成,以减少对系统性能的影响。软中断可以被内核抢占,但它们自己之间不会抢占彼此,因此可以保证一定程度的执行顺序。
在早期的 Linux 内核中,内核是非抢占的,意味着一旦一个进程进入内核模式执行系统调用或者内核代码,它会一直运行到返回到用户模式,除非它自己放弃 CPU。在这种模式下,一个正在执行的内核路径不会被另一个更高优先级的任务抢占。
随着 Linux 内核的发展,为了提高系统的响应性和实时性,引入了「抢占式内核」(PREEMPT) 功能。从 2.6 版本开始,Linux 内核提供了可配置的抢占模型。抢占式内核允许在执行内核代码时(不包括关键区,即临界区和中断处理程序),根据需要将 CPU 让给更高优先级的任务,这在多任务系统中尤为重要,能够减少任务响应时间,提高系统的实时性。
对于抢占式内核,一旦有更高优先级的任务需要运行,当前任务可以在内核态被抢占,只要它们不在临界区内。这种特性对于需要快速响应外部事件的实时操作系统尤为重要。
关于软中断(softirq)是 Linux 内核中一种底层的机制,用来处理非即时的中断处理工作。它们通常发生在两种情况下:
1. 硬件中断的底半部(bottom half)处理:当硬件产生中断时,中断处理被分为两部分。上半部(顶半部,top half)是指那些必须立即执行的处理工作,由硬件中断直接触发并立即执行;下半部是指可以推迟处理的、不那么急迫的工作,通常由软中断来处理。
2. 在内核中需要异步处理的其他情况。
软中断可以被抢占,它们的执行可以在任何非临界的内核上下文中发生,但是软中断本身不会主动放弃处理器控制权。这意味着一旦软中断开始执行,它们会运行到完成,除非它们被硬中断或者硬件中断的上半部抢占。这样设计是为了避免复杂的锁依赖和避免软中断处理被无限期地推迟。
总结来说,最新的 Linux 内核提供了抢占式内核的功能,可以通过配置选项开启或关闭。而软中断作为内核中的一种机制,用于处理那些可以延后而非即时处理的工作,与内核抢占机制相辅相成,共同提高系统的效率和响应速度。