1. 中断基础概念
中断(Interrupt)是硬件与软件之间的一种异步事件通知机制。当外设需要 CPU 处理数据或状态变化时,通过中断信号线向 CPU 发送一个电信号,CPU 暂停当前正在执行的指令流,转而执行预先注册好的中断服务程序(ISR),处理完成后再恢复原来的执行流。中断机制是操作系统实现多任务、实时响应和高性能 I/O 的基石。
1.1 什么是中断
中断的本质是 CPU 对异步事件的响应。与轮询(Polling)方式相比,中断避免了 CPU 持续占用资源去检查设备状态,从而大幅提升系统整体效率。
| 对比维度 | 中断方式 | 轮询方式 |
|---|---|---|
| CPU 利用率 | 高,无事时 CPU 可执行其他任务 | 低,CPU 需不断检查设备状态 |
| 响应延迟 | 低,事件发生立即通知 | 高,取决于轮询间隔 |
| 实现复杂度 | 较高,需中断控制器和向量表 | 简单,仅需循环读取状态寄存器 |
| 适用场景 | 低频率、突发性事件(网卡、磁盘) | 高频率、可预测事件(定时器) |
1.2 中断向量与中断请求(IRQ)
中断向量(Interrupt Vector) 是一个数字编号,每个中断源对应一个唯一的向量号。CPU 收到中断信号后,根据向量号在中断描述符表(IDT)中查找对应的中断服务程序入口地址。在 x86 架构中,向量号范围通常为 0–255,其中 0–31 为 CPU 内部异常和 NMI,32–255 为外部硬件中断。
中断请求(IRQ) 是硬件设备向中断控制器(如 APIC、IO-APIC)发送的电信号。每个设备被分配一个 IRQ 号,中断控制器将 IRQ 映射为中断向量,并转发给 CPU。在 Linux 中,/proc/interrupts 文件列出了当前系统中所有注册的 IRQ 及其统计信息。
cat /proc/interrupts 可以查看每个 CPU 核处理的中断次数分布,这是判断中断是否均衡的第一手数据。
# 示例:查看 /proc/interrupts 输出片段
CPU0 CPU1 CPU2 CPU3
0: 45 0 0 0 IO-APIC 2-edge timer
1: 3 0 0 0 IO-APIC 1-edge i8042
8: 1 0 0 0 IO-APIC 8-edge rtc0
24: 123456 98765 87654 76543 PCI-MSI 524288-edge eth0
25: 0 0 0 0 PCI-MSI 524289-edge eth1
1.3 中断处理流程
一次完整的中断处理从硬件信号产生到软件处理结束,分为上半部(Top Half)和下半部(Bottom Half)两个阶段。上半部在中断上下文中执行,要求快速完成;下半部在软中断或 tasklet 中执行,可延迟处理。
1.4 中断处理的关键数据结构
Linux 内核使用以下核心数据结构管理中断:
- irq_desc:每个 IRQ 对应一个
irq_desc结构体,包含中断状态、处理函数链表、亲和性掩码等信息。 - irqaction:描述一个中断处理动作,包含处理函数指针、设备名称、触发方式等。多个设备可共享同一 IRQ。
- 中断描述符表(IDT):x86 架构中,IDT 将中断向量号映射到对应的门描述符,门描述符中包含段选择子和偏移量,指向 ISR 入口。
// Linux 内核 irq_desc 结构体简化定义
struct irq_desc {
struct irq_data irq_data; // 中断数据,包含向量号、芯片信息
struct irqaction *action; // 中断处理动作链表
unsigned int status_use_accessors; // 中断状态标志
cpumask_var_t affinity; // CPU 亲和性掩码
unsigned int irq_count; // 中断计数
// ... 其他字段
};
/proc/irq/{IRQ}/node 查看。
1.5 中断亲和性与负载均衡
每个 IRQ 都有一个 CPU 亲和性掩码(affinity mask),决定该中断可以被哪些 CPU 核处理。默认情况下,中断可能集中在 CPU0 上,导致单核负载过高。通过设置亲和性掩码,可以将中断分散到多个 CPU 核,实现中断负载均衡。
| 操作 | 命令/接口 | 说明 |
|---|---|---|
| 查看当前亲和性 | cat /proc/irq/{IRQ}/smp_affinity |
输出十六进制掩码,如 00000001 表示仅 CPU0 |
| 手动设置亲和性 | echo 0f > /proc/irq/{IRQ}/smp_affinity |
将中断分配给 CPU0-3(二进制 1111) |
| 查看中断分布 | cat /proc/interrupts |
每列对应一个 CPU 核的中断计数 |
| 使用 irqbalance | systemctl start irqbalance |
自动动态调整中断亲和性 |