1. 中断基础概念
中断(Interrupt)是硬件与软件之间异步通信的核心机制,也是驱动开发和网络协议栈协作的基石。本章从最基础的定义出发,逐步构建中断向量、上下文、优先级等关键概念,为后续理解软中断(SoftIRQ)与网络协议栈的协作打下坚实基础。
1.1 中断定义与本质
中断是一种由硬件或软件触发的、使处理器暂停当前执行流、转而执行特定处理程序的机制。其本质是异步事件处理——CPU 无需轮询等待设备状态变化,而是由设备主动“通知”CPU。
核心特征:
- 异步性:中断发生时间不可预测,与当前执行流无关。
- 抢占性:中断处理程序优先级高于普通进程,可抢占当前任务。
- 透明性:中断处理完成后,被中断的进程应能恢复执行,仿佛未发生中断。
驱动开发视角:网卡驱动通过中断通知 CPU 有数据包到达,这是网络协议栈接收路径的起点。如果中断处理不当,会导致丢包或性能下降。
1.2 中断向量
中断向量(Interrupt Vector)是一个整数编号,用于唯一标识一个中断源。CPU 收到中断后,通过向量号在中断描述符表(IDT)中索引,找到对应的处理函数入口地址。
| 向量范围 | 类型 | 说明 |
|---|---|---|
| 0 – 31 | 异常与陷阱 | CPU 内部异常(如缺页 #PF、除零 #DE),不可屏蔽 |
| 32 – 255 | 外部中断(IRQ) | 由硬件设备触发,通过 I/O APIC 路由 |
| 0x80 | 系统调用 | Linux 使用 int 0x80 或 syscall 指令实现用户态→内核态切换 |
驱动开发注意:在 x86 架构上,Linux 内核将 IRQ 0–15 映射到向量 32–47(对应传统 PIC),而 MSI/MSI-X 中断可分配到任意空闲向量。注册中断时,
request_irq() 的第一个参数就是 IRQ 号,内核会自动分配向量。
1.3 中断上下文
中断上下文(Interrupt Context)是指 CPU 在执行中断服务例程时所处的特殊运行环境。与进程上下文不同,中断上下文具有以下关键特征:
- 不可睡眠:中断上下文不在任何进程的调度范围内,不能调用
schedule()、wait_event()等可能引起睡眠的函数。 - 不可持有互斥锁:只能使用自旋锁(spinlock)等不会睡眠的同步机制。
- 栈空间有限:每个 CPU 有独立的中断栈(通常 4KB–16KB),必须避免深度递归或大局部变量。
- 可被更高优先级中断抢占:除非显式关闭本地中断。
| 特性 | 进程上下文 | 中断上下文 |
|---|---|---|
| 可睡眠 | 是 | 否 |
| 可持有互斥锁 | 是 | 否(仅自旋锁) |
| 当前进程指针 (current) | 有效 | 指向被中断的进程(不可依赖) |
| 栈大小 | 8KB / 16KB | 4KB – 16KB(独立中断栈) |
| 典型操作 | 系统调用、文件读写 | ACK 中断、拷贝数据、触发软中断 |
驱动最佳实践:中断服务例程应尽可能短小,只做最紧急的工作(如读取硬件状态寄存器、清除中断标志),将耗时处理推迟到软中断或工作队列中。这正是 Linux 网络协议栈使用软中断(SoftIRQ)处理数据包的原因。
1.4 中断优先级
中断优先级决定了当多个中断同时发生时,CPU 先处理哪一个。Linux 内核在 x86 架构上使用以下优先级模型:
- 硬件优先级(I/O APIC):每个 IRQ 可编程分配优先级(0–15),数值越小优先级越高。
- CPU 中断屏蔽级别(EFLAGS.IF):通过
local_irq_disable()可临时屏蔽所有外部中断。 - 软中断优先级:在中断上下文之上,软中断(SoftIRQ)也有优先级排序(HI_SOFTIRQ > TIMER_SOFTIRQ > NET_TX_SOFTIRQ > NET_RX_SOFTIRQ > ...)。
| 优先级层级 | 机制 | 说明 |
|---|---|---|
| 最高 | NMI(不可屏蔽中断) | 硬件错误、看门狗,无法被屏蔽 |
| 高 | CPU 异常(#PF、#GP 等) | 同步异常,优先级高于外部中断 |
| 中 | 外部可屏蔽中断(IRQ) | 设备中断,受 IF 标志控制 |
| 低 | 软中断(SoftIRQ) | 在中断返回时执行,可被新中断抢占 |
| 最低 | tasklet / 工作队列 | 可睡眠,调度延迟较大 |
网络协议栈关联:网卡中断(IRQ)属于“中”优先级,而网络协议栈的接收处理(NET_RX_SOFTIRQ)属于“低”优先级软中断。这种分层设计保证了网卡能快速响应新数据包,而协议栈处理不会阻塞中断响应。
1.5 中断与软中断的协作关系
在 Linux 网络协议栈中,中断处理被明确拆分为两个阶段:
- 上半部(Top Half):在中断上下文中执行,完成最紧急的硬件操作(如读取数据包、清除中断标志),然后触发软中断。
- 下半部(Bottom Half):在软中断上下文中执行,完成协议栈处理(如 IP 层、TCP/UDP 层处理),可被新中断抢占但不可睡眠。
关键协作流程:
- 网卡产生中断 → CPU 执行 ISR(上半部)
- ISR 将数据包放入 CPU 私有队列,调用
__raise_softirq_irqoff(NET_RX_SOFTIRQ) - 中断返回前,
do_softirq()检查挂起的软中断并执行 - 网络协议栈在软中断中完成数据包处理
这种协作机制既保证了中断响应的实时性,又避免了在中断上下文中执行复杂的协议栈逻辑导致系统不稳定。