1. 中断基础概念

中断(Interrupt)是硬件与软件之间异步通信的核心机制,也是驱动开发和网络协议栈协作的基石。本章从最基础的定义出发,逐步构建中断向量、上下文、优先级等关键概念,为后续理解软中断(SoftIRQ)与网络协议栈的协作打下坚实基础。

1.1 中断定义与本质

中断是一种由硬件或软件触发的、使处理器暂停当前执行流、转而执行特定处理程序的机制。其本质是异步事件处理——CPU 无需轮询等待设备状态变化,而是由设备主动“通知”CPU。

核心特征:
  • 异步性:中断发生时间不可预测,与当前执行流无关。
  • 抢占性:中断处理程序优先级高于普通进程,可抢占当前任务。
  • 透明性:中断处理完成后,被中断的进程应能恢复执行,仿佛未发生中断。
驱动开发视角:网卡驱动通过中断通知 CPU 有数据包到达,这是网络协议栈接收路径的起点。如果中断处理不当,会导致丢包或性能下降。
中断触发与处理流程 设备产生中断 中断控制器 CPU 响应中断 执行 ISR 说明:中断控制器(如 APIC)负责仲裁多个中断源,决定优先级,并将中断向量号发送给 CPU。 CPU 根据向量号查找中断描述符表(IDT),跳转到对应的中断服务例程(ISR)。 保存上下文 处理中断 恢复上下文 返回原执行流

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 号,内核会自动分配向量。
中断向量 → IDT → ISR 查找过程 向量号 0x32 中断描述符表 (IDT) 0x00: #DE (除零异常) 0x01: #DB (调试异常) ... 0x32: gate → ISR_eth_rx 0x33: gate → ISR_timer ... ISR_eth_rx() ISR_timer()

1.3 中断上下文

中断上下文(Interrupt Context)是指 CPU 在执行中断服务例程时所处的特殊运行环境。与进程上下文不同,中断上下文具有以下关键特征:

  • 不可睡眠:中断上下文不在任何进程的调度范围内,不能调用 schedule()、wait_event() 等可能引起睡眠的函数。
  • 不可持有互斥锁:只能使用自旋锁(spinlock)等不会睡眠的同步机制。
  • 栈空间有限:每个 CPU 有独立的中断栈(通常 4KB–16KB),必须避免深度递归或大局部变量。
  • 可被更高优先级中断抢占:除非显式关闭本地中断。
特性 进程上下文 中断上下文
可睡眠 是 否
可持有互斥锁 是 否(仅自旋锁)
当前进程指针 (current) 有效 指向被中断的进程(不可依赖)
栈大小 8KB / 16KB 4KB – 16KB(独立中断栈)
典型操作 系统调用、文件读写 ACK 中断、拷贝数据、触发软中断
驱动最佳实践:中断服务例程应尽可能短小,只做最紧急的工作(如读取硬件状态寄存器、清除中断标志),将耗时处理推迟到软中断或工作队列中。这正是 Linux 网络协议栈使用软中断(SoftIRQ)处理数据包的原因。
中断上下文 vs 进程上下文 进程上下文 可睡眠 可持有互斥锁 current 有效 大栈空间 中断上下文 不可睡眠 ❌ 仅自旋锁 current 不可靠 栈空间有限

1.4 中断优先级

中断优先级决定了当多个中断同时发生时,CPU 先处理哪一个。Linux 内核在 x86 架构上使用以下优先级模型:

  1. 硬件优先级(I/O APIC):每个 IRQ 可编程分配优先级(0–15),数值越小优先级越高。
  2. CPU 中断屏蔽级别(EFLAGS.IF):通过 local_irq_disable() 可临时屏蔽所有外部中断。
  3. 软中断优先级:在中断上下文之上,软中断(SoftIRQ)也有优先级排序(HI_SOFTIRQ > TIMER_SOFTIRQ > NET_TX_SOFTIRQ > NET_RX_SOFTIRQ > ...)。
优先级层级 机制 说明
最高 NMI(不可屏蔽中断) 硬件错误、看门狗,无法被屏蔽
高 CPU 异常(#PF、#GP 等) 同步异常,优先级高于外部中断
中 外部可屏蔽中断(IRQ) 设备中断,受 IF 标志控制
低 软中断(SoftIRQ) 在中断返回时执行,可被新中断抢占
最低 tasklet / 工作队列 可睡眠,调度延迟较大
网络协议栈关联:网卡中断(IRQ)属于“中”优先级,而网络协议栈的接收处理(NET_RX_SOFTIRQ)属于“低”优先级软中断。这种分层设计保证了网卡能快速响应新数据包,而协议栈处理不会阻塞中断响应。
中断优先级层次结构 NMI(不可屏蔽中断) CPU 异常(#PF, #GP, #DE) 外部可屏蔽中断(IRQ 设备中断) 软中断(SoftIRQ:NET_RX, NET_TX, TIMER...) tasklet / 工作队列(可睡眠,延迟处理) 优先级递增

1.5 中断与软中断的协作关系

在 Linux 网络协议栈中,中断处理被明确拆分为两个阶段:

  • 上半部(Top Half):在中断上下文中执行,完成最紧急的硬件操作(如读取数据包、清除中断标志),然后触发软中断。
  • 下半部(Bottom Half):在软中断上下文中执行,完成协议栈处理(如 IP 层、TCP/UDP 层处理),可被新中断抢占但不可睡眠。
关键协作流程:
  1. 网卡产生中断 → CPU 执行 ISR(上半部)
  2. ISR 将数据包放入 CPU 私有队列,调用 __raise_softirq_irqoff(NET_RX_SOFTIRQ)
  3. 中断返回前,do_softirq() 检查挂起的软中断并执行
  4. 网络协议栈在软中断中完成数据包处理

这种协作机制既保证了中断响应的实时性,又避免了在中断上下文中执行复杂的协议栈逻辑导致系统不稳定。