1. 什么是软中断?
在 Linux 内核中,中断通常分为两种:
- 硬中断(HardIRQ):由硬件设备触发,要求处理器立即响应。
- 软中断(SoftIRQ):由硬中断触发的一种软层次的延迟任务,通常用于完成硬中断上下文中未完成的工作。
软中断的特点:
- 它们具有更低的优先级,只有在硬中断完成后才能被调度。
- 可以在多个 CPU 上并发执行,但同一类型的软中断在一个 CPU 上是串行的。
- 不允许睡眠(即无法调用阻塞操作)。
2. 软中断的用途
软中断广泛应用于内核中的以下场景:
- 网络协议栈:如网络包的接收和处理(
NET_RX
)、发送完成的处理(NET_TX
)。 - 任务调度:如调度器相关的负载均衡工作。
- 定时器:延时任务的执行。
3. 软中断的工作机制
3.1 软中断的触发和挂起
软中断由硬中断触发,在硬中断处理过程中,内核会将需要延迟处理的任务挂起,标记为软中断待处理。
- 挂起软中断:
void raise_softirq(unsigned int nr); //nr
是软中断的编号(如NET_RX
或TIMER
)。
3.2 软中断的执行
软中断的执行入口是 __do_softirq()
,它会检查所有挂起的软中断并逐一处理。执行软中断的场景主要有:
- 硬中断结束后: 当硬中断处理完成时,如果有挂起的软中断,内核会立即调用
__do_softirq()
执行它。 - ksoftirqd 内核线程: 如果软中断处理时间较长,内核会将其移交给一个内核线程
ksoftirqd
执行,以避免长时间占用硬中断上下文。
void __do_softirq(void)
{
// 遍历所有挂起的软中断类型并执行对应处理函数
for_each_softirq_action(action)
action->handler();
}
4. 软中断类型
内核定义了一组固定的软中断类型,可以通过查看源码 include/linux/interrupt.h
找到它们。常见的软中断包括:
HI
: 高优先级任务。TIMER
: 定时器任务。NET_RX
: 网络接收包的处理。NET_TX
: 网络发送包的完成处理。BLOCK
: 块设备相关任务。TASKLET
: 任务执行的延迟处理。RCU
: RCU(Read-Copy-Update)相关任务。
可以通过命令查看当前系统中各类软中断的统计数据:
cat /proc/softirqs
5. 软中断的调度与分配
5.1 CPU 选择
软中断通常由硬中断触发的同一个 CPU 处理,这样可以避免跨 CPU 的上下文切换开销。但内核会在以下情况下调整:
- 如果一个 CPU 长时间被软中断占用,则调度器会将部分软中断移交给其他 CPU。
- 在 NUMA 架构中,软中断的分配会优先考虑 CPU 和设备的亲和性。
5.2 ksoftirqd
的作用
每个 CPU 都有一个 ksoftirqd
线程(命名为 ksoftirqd/N
,N
是 CPU 编号)。如果软中断的处理时间过长,会通过 ksoftirqd
来完成。这可以有效避免软中断阻塞其他任务的执行。
6. 软中断与硬中断的对比
特性 | 硬中断 | 软中断 |
---|---|---|
触发来源 | 由硬件设备直接触发 | 由硬中断挂起 |
优先级 | 高优先级,实时性强 | 优先级低,延迟执行 |
执行上下文 | 硬中断上下文,不可阻塞 | 中断上下文或内核线程,不可阻塞 |
可并发性 | 单 CPU 上串行 | 不同类型可以并发 |
7. 软中断相关的调优和排查
7.1 调整软中断的处理 CPU
通过 /proc/irq/<IRQ>/smp_affinity
可以修改硬中断和软中断的 CPU 亲和性。
7.2 查看软中断的负载
通过 /proc/softirqs
监控各类软中断的 CPU 分布。如果发现某个软中断在某个 CPU 上的负载过高,可以尝试调整中断亲和性。
8. 总结
软中断是 Linux 内核中一个重要的机制,用于处理需要延迟执行的任务。它通过挂起和分级调度的方式,将复杂任务从硬中断中分离,提高了系统的实时响应能力和吞吐性能。理解软中断的机制和调度方式,对系统性能优化和问题排查至关重要。