2. Linux中断子系统基础:中断向量表、中断描述符、中断处理流程(上半部与下半部)
中断是操作系统响应硬件事件的异步机制,是驱动延迟分析的核心对象。本章从硬件向量表到软件处理流程,建立中断子系统的完整知识框架。
2.1 中断向量表(IDT)
在x86架构中,中断向量表(Interrupt Descriptor Table, IDT)是CPU用于查找中断处理入口的256项结构。每个中断或异常对应一个0–255的向量号。
| 向量范围 | 类型 | 典型用途 |
|---|---|---|
| 0–31 | 异常与NMI | 除零、缺页、调试、机器检查等 |
| 32–47 | IRQ(硬件中断) | 定时器、键盘、磁盘、网卡等 |
| 48–255 | 软件中断与自定义 | 系统调用(0x80)、IPI、分配向量 |
关键点:向量号0–31由Intel/AMD固定,32–47对应传统PIC的IRQ0–IRQ15,48以上由内核动态分配(如MSI-X中断)。
Perf关联:PMU溢出中断通常占用一个高向量号(如236+),通过
perf_event_interrupt入口处理。向量号可在/proc/interrupts中查看。
2.2 中断描述符与irq_desc
内核使用struct irq_desc管理每个中断源的状态、处理函数链、统计信息和亲和性。每个IRQ号对应一个irq_desc实例,存储在全局数组irq_desc[]中。
// include/linux/irqdesc.h (简化结构)
struct irq_desc {
struct irq_common_data irq_common_data;
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs; // 每个CPU的中断计数
irq_flow_handler_t handle_irq; // 高层流控处理
struct irqaction *action; // 处理函数链表
unsigned int status_use_accessors;
struct irq_chip *chip; // 硬件控制器操作
struct irq_domain *irq_data.domain;
...
};
| 字段 | 作用 | 延迟分析关注点 |
|---|---|---|
handle_irq |
高层中断流控(如handle_edge_irq) | 流控函数执行时间 |
action |
设备驱动注册的处理函数链表 | 上半部执行时间 |
kstat_irqs |
每个CPU的中断计数 | 中断频率与分布 |
chip |
硬件操作(mask/unmask/ack) | 硬件访问延迟 |
性能陷阱:多个设备共享同一IRQ号时,
action链表会串行遍历所有处理函数。共享中断的累积执行时间直接影响调度延迟。
2.3 中断处理流程:上半部与下半部
Linux将中断处理拆分为两个阶段,以平衡实时性与吞吐量:
- 上半部(Top Half):在中断上下文中立即执行,关中断或屏蔽当前IRQ线。完成硬件ACK、数据拷贝、清除中断标志等紧急操作。必须短小精悍。
- 下半部(Bottom Half):推迟到开中断后执行,处理耗时逻辑。内核提供三种机制:软中断(SoftIRQ)、tasklet、工作队列(workqueue)。
延迟分析核心:上半部执行期间本地CPU关中断,直接阻塞调度器时钟中断和所有其他中断。上半部执行时间 = 不可抢占的延迟增量。下半部虽然开中断,但软中断/ tasklet仍运行在中断上下文中,优先级高于普通进程。
2.3.1 完整处理流程
- CPU收到中断信号,硬件自动压栈SS/RSP/RFLAGS/CS/RIP,跳转到IDT中对应的入口。
- 入口代码保存寄存器,调用
do_IRQ()或common_interrupt()。 - 根据IRQ号找到
irq_desc,调用handle_irq流控函数。 - 流控函数调用
action链表中的handler(上半部)。 - 上半部返回后,检查是否有待处理的软中断,执行
do_softirq()。 - 软中断处理完后,恢复寄存器,执行
iretq返回被中断的上下文。
2.3.2 下半部机制对比
| 机制 | 执行上下文 | 可睡眠 | 并发模型 | 典型延迟 |
|---|---|---|---|---|
| SoftIRQ | 中断上下文 | 否 | 同类型可并行(多CPU) | 低(~μs级) |
| Tasklet | 中断上下文 | 否 | 串行(同类型单CPU) | 中(~10μs级) |
| Workqueue | 进程上下文 | 是 | 由kworker线程调度 | 高(~ms级) |
Perf观测点:使用
perf sched可以观测workqueue延迟;使用perf stat -e irq_vectors:*可以统计各向量中断频率;使用perf probe可以动态测量上半部执行时间。
2.4 中断上下文与调度延迟的关系
中断上下文与普通进程上下文的关键区别决定了延迟分析的切入点:
- 不可抢占窗口:上半部执行期间,当前CPU无法响应调度器时钟中断,无法触发进程切换。这个窗口直接累加到调度延迟中。
- 软中断优先级:软中断在
do_softirq()中执行,优先级高于任何用户态进程。大量网络软中断(NET_RX_SOFTIRQ)会显著延迟SCHED_OTHER进程的调度。 - 中断嵌套:高优先级中断可以抢占低优先级中断的上半部,但所有上半部都关本地中断,因此上半部之间不会嵌套。
典型问题:网卡中断上半部执行时间过长(如大量拷贝),导致音频中断(通常高优先级)被延迟,造成音频卡顿。这是中断上下文驱动延迟的经典案例。