1. 中断基础:什么是中断、中断向量表、中断处理流程
中断(Interrupt)是硬件或软件向处理器发送的一种异步信号,用于通知处理器发生了需要立即关注的事件。在 Linux 内核中,中断是驱动 I/O 设备、网络包收发、定时器以及异常处理的核心机制。理解中断的基础概念、向量表结构以及上下半部处理流程,是后续配置 irqbalance 和进行 CPU 绑定 的前提。
1.1 什么是中断
中断本质上是一种 事件通知机制。当外部设备(如网卡、磁盘控制器)完成数据传输,或内部定时器到期,设备通过中断控制器(如 APIC、GIC)向 CPU 发送一个电信号。CPU 在每条指令执行完毕后检查中断引脚,若检测到中断信号且中断未被屏蔽,则暂停当前任务,保存上下文,跳转到预定义的中断处理程序执行。
- 异步性:中断的发生与 CPU 当前执行的指令流无关,属于硬件驱动的异步事件。
- 优先级:中断控制器为每个中断源分配优先级,高优先级中断可以抢占低优先级中断的处理。
- 可屏蔽性:CPU 可以通过 EFLAGS 中的 IF 标志位(x86)或 PSTATE 中的 I 位(ARM64)全局屏蔽/开启中断。
在 Linux 内核中,中断被分为两种类型:
| 类型 | 触发方式 | 典型来源 | 是否可屏蔽 |
|---|---|---|---|
| 硬件中断 | 外部设备通过中断控制器引脚触发 | 网卡(RX/TX)、磁盘(NVMe/SATA)、USB | 是(通过 IF 标志或中断掩码) |
| 软件中断 | CPU 执行 INT n 指令触发 | 系统调用(int 0x80)、异常(缺页、除零) | 部分可屏蔽(异常不可屏蔽) |
1.2 中断向量表
中断向量表(Interrupt Vector Table, IVT)是操作系统或固件在内存中维护的一张表,表中每个条目(向量)对应一个中断号,存储着该中断对应的处理程序入口地址。当 CPU 收到中断信号时,根据中断号从向量表中取出地址,跳转执行。
在 x86 架构中,中断向量表在实模式下位于物理地址 0x0000 处,每个向量占 4 字节(段:偏移)。在保护模式下,由 中断描述符表(IDT) 替代,每个描述符占 8 字节,包含选择子、偏移量、类型和 DPL 等信息。Linux 内核在启动时初始化 IDT,将每个中断向量绑定到对应的内核处理函数。
1.3 中断处理流程:上半部与下半部
中断处理程序必须快速执行,因为中断期间 CPU 会屏蔽同级或更低优先级的中断,导致系统无法响应其他事件。然而,很多设备(如网卡)在中断处理中需要完成大量工作(如拷贝数据包、协议栈处理)。为了解决这个矛盾,Linux 内核将中断处理拆分为两个阶段:上半部(Top Half) 和 下半部(Bottom Half)。
上半部(硬中断上下文)
- 执行环境:在中断上下文中运行,不可睡眠,不可阻塞。
- 职责:保存硬件状态、清除设备中断标志、将数据从设备 FIFO 拷贝到内存缓冲区、调度下半部。
- 特点:必须极快完成(通常微秒级),否则会导致中断丢失或系统延迟飙升。
下半部(软中断 / tasklet / workqueue)
- 执行环境:在软中断上下文或进程上下文中运行,部分实现可以睡眠(workqueue)。
- 职责:完成上半部剩余的耗时工作,如协议栈处理、数据分发、唤醒用户态进程。
- 机制:Linux 提供三种下半部实现机制:软中断(SoftIRQ)、tasklet(基于软中断构建)、工作队列(workqueue)。
1.4 中断处理中的关键数据结构
Linux 内核使用 irq_desc 结构体描述每个中断号的状态和处理函数链。每个 irq_desc 包含中断状态标志、硬件控制器操作函数集(struct irq_chip)、以及一个或多个 irqaction 实例,后者保存了用户注册的中断处理函数(上半部)。
// 内核源码 include/linux/irqdesc.h (简化)
struct irq_desc {
struct irq_common_data irq_common_data;
struct irq_chip *chip; // 硬件控制器操作
struct irqaction *action; // 中断处理函数链表
unsigned int status_use_accessors;
unsigned int depth; // 嵌套深度
...
};
// 用户注册中断处理函数
// 驱动调用 request_irq(irq, handler, flags, name, dev)
// 内核内部创建 irqaction 实例并挂入 irq_desc->action 链表
/proc/interrupts 可以查看每个 CPU 上每个中断号的发生次数。这是后续分析中断亲和性是否生效的第一手工具。
1.5 中断亲和性的概念引入
在多核系统中,每个中断可以被路由到特定的 CPU 核心进行处理。中断亲和性(IRQ Affinity)决定了哪个 CPU 核心负责处理某个中断。默认情况下,中断可能被分配到任意核心,导致 CPU 缓存抖动和跨 NUMA 访问延迟。通过设置 /proc/irq/<IRQ>/smp_affinity 或使用 irqbalance 守护进程,可以显式控制中断的 CPU 分布,从而提升网络吞吐量和降低延迟。
本章后续内容将深入讲解如何查看当前中断分布、如何手动绑定中断到指定 CPU,以及 irqbalance 的自动均衡策略。