少于 1 分钟阅读 次阅读

软中断是 Linux 内核用于处理中断下半部的一种核心机制,它允许内核在合适的时机执行一些对时间敏感但无需立即完成的任务,是保证系统响应性能与吞吐量的重要设计。

一、主要概念

软中断:在内核编译时静态分配、由固定数组管理的一种可延迟执行机制,用于处理中断下半部任务,保证对时间要求严格的核心操作能及时执行。
softirq_action 结构:表示一个软中断的基本单元,其内部只有一个函数指针 action,指向该软中断的实际处理函数。
softirq_vec 数组:内核中一个包含 32 个 softirq_action 结构的静态数组,每个注册的软中断占据其中一项,当前内核通常只使用其中一部分。
软中断处理程序:实际执行软中断任务的函数,其函数原型为 void handler(struct softirq_action *),运行时内核会传入对应的 softirq_action 结构指针。
触发软中断:通过调用 raise_softirq() 等函数将某个软中断标记为“待处理”状态,等待内核在适当时候执行。
do_softirq() 函数:软中断的执行入口,该函数检查所有待处理的软中断,并依次调用其处理程序。


二、软中断的特点与设计

软中断的设计注重性能和可扩展性,其核心特点包括:

  • 静态分配:软中断类型在内核编译时通过枚举静态定义,无法在运行时动态注册或注销,当前内核最多支持 32 种软中断。
  • 无自我抢占:同一个 CPU 上,一个软中断不会抢占另一个正在运行的软中断,能够抢占软中断的只有硬件中断处理程序。
  • 支持多处理器并发:同一种软中断可以在不同 CPU 上同时执行,因此其处理程序必须妥善处理并发访问,通常通过每 CPU 数据或锁来保护共享数据。
  • 固定优先级:软中断的优先级由其在 softirq_vec 数组中的索引决定,索引越小优先级越高,执行顺序也越靠前。

当前内核中已定义的软中断类型及其优先级如下表所示(常见部分):

软中断类型 优先级 用途描述
HI_SOFTIRQ 0 高优先级 tasklet
TIMER_SOFTIRQ 1 定时器下半部
NET_TX_SOFTIRQ 2 发送网络数据包
NET_RX_SOFTIRQ 3 接收网络数据包
BLOCK_SOFTIRQ 4 块设备相关操作
TASKLET_SOFTIRQ 5 普通优先级 tasklet
SCHED_SOFTIRQ 6 调度器相关工作
HRTIMER_SOFTIRQ 7 高精度定时器
RCU_SOFTIRQ 8 RCU 锁处理

注:tasklet 本身是建立在软中断(尤其是 HI_SOFTIRQTASKLET_SOFTIRQ)之上的机制,其设计更简单、对并发控制要求更低,适用于大多数下半部场景。


三、软中断的执行流程

软中断的执行可概括为三个步骤:注册 → 触发 → 执行

1. 注册软中断

在编译时在枚举列表中添加新项,并在运行时调用 open_softirq() 函数注册处理程序,例如网络子系统注册发送和接收软中断:

open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

2. 触发软中断

在需要执行软中断任务的地方(尤其是硬件中断处理程序返回前),调用 raise_softirq()raise_softirq_irqoff() 将其标记为挂起状态。例如网络子系统触发发送软中断:

raise_softirq(NET_TX_SOFTIRQ);

3. 执行软中断

内核在以下三种时机检查并执行待处理软中断:

  1. 从硬件中断处理程序返回时;
  2. 在专门的 ksoftirqd 内核线程中;
  3. 在显式调用软中断处理的代码中(如网络子系统)。

实际执行工作由 do_softirq() 完成,其核心逻辑简化如下:

u32 pending = local_softirq_pending(); // 获取待处理软中断位图
if (pending) {
    set_softirq_pending(0);            // 清空位图
    struct softirq_action *h = softirq_vec;
    do {
        if (pending & 1)
            h->action(h);               // 执行对应软中断处理程序
        h++;
        pending >>= 1;
    } while (pending);
}

该函数遍历 32 位位图,若某一位为 1,则调用数组中对应项的处理函数。由于位图最多 32 位,循环次数有限,确保了执行效率。


四、软中断与 tasklet 的选择

虽然软中断功能强大,但因其可并发执行、需开发者自行处理多 CPU 同步,所以内核推荐在大多数情况下使用 tasklet,因为:

  • tasklet 基于软中断实现,但同一 tasklet 不能在多个 CPU 上同时运行,简化了同步需求;
  • tasklet 可动态创建,使用更灵活;
  • 只在需要极高性能、能自行高效处理锁、且需多 CPU 并发的场景(如网络、SCSI 子系统)才直接使用软中断。

留下评论