1. 中断基础概念:中断定义、中断类型与处理流程

1.1 中断的定义与本质

中断(Interrupt)是计算机系统中一种核心的硬件-软件协同机制,它允许硬件设备(如网卡、磁盘控制器、定时器)或软件指令异步地通知处理器,需要立即关注某个事件。从处理器视角看,中断本质上是一条“控制流切换指令”——它打断当前正在执行的指令流,保存现场,跳转到一个预定义的中断服务例程(ISR, Interrupt Service Routine)执行,执行完毕后再恢复现场,继续执行被打断的程序。

关键理解:中断不是轮询(Polling)。轮询是CPU主动反复检查设备状态,浪费CPU周期;中断是设备主动通知CPU,实现“无事不扰,有事即报”的高效事件驱动模型。

1.2 中断类型:同步中断 vs 异步中断

中断根据触发源和发生时机,分为两大类:同步中断(也称异常,Exception)和异步中断(也称硬件中断,Hardware Interrupt)。两者的核心区别在于:同步中断由指令执行本身触发,与当前指令流同步;异步中断由外部硬件事件触发,与当前指令流异步。

对比维度 同步中断(异常) 异步中断(硬件中断)
触发源 CPU内部:指令执行错误(除零、缺页)、系统调用(int 0x80/syscall) CPU外部:硬件设备(网卡、磁盘、定时器)、外部信号
发生时机 指令执行期间,可预测(与指令流同步) 任意时刻,不可预测(与指令流异步)
可重入性 通常不可重入,同一异常嵌套会导致双重故障(Double Fault) 可嵌套,高优先级中断可打断低优先级中断服务
典型例子 #PF(缺页异常)、#GP(通用保护异常)、#DE(除零异常) IRQ(中断请求):网卡收包、磁盘I/O完成、时钟滴答
处理方式 通常由操作系统异常处理程序修复或杀死进程 由设备驱动程序的中断服务例程(ISR)处理
实践提示:在Linux内核中,同步中断通过IDT(中断描述符表)的异常门(Trap Gate)处理,异步中断通过中断门(Interrupt Gate)处理。两者的关键区别在于:中断门会自动清除IF标志(禁止中断嵌套),而异常门不会。

1.3 中断处理流程概述

一次完整的中断处理流程,从硬件设备发出中断信号到CPU执行完中断服务例程,通常包含以下6个阶段。理解这个流程是后续配置MSI-X多向量中断和CPU亲缘性的基础。

  1. 设备发起中断请求:硬件设备(如网卡)检测到需要CPU关注的事件(如数据包到达),通过中断控制器(如APIC、MSI-X Capability)向CPU发送中断信号。
  2. 中断控制器仲裁与路由:中断控制器根据优先级、亲和性设置(Affinity)、向量号(Vector Number)决定将中断发送给哪个CPU核心。
  3. CPU中断响应(Interrupt Acknowledge):CPU在每条指令执行完毕后检查INTR引脚或Local APIC的中断请求寄存器。若检测到待处理中断且IF标志为1(允许中断),则进入中断响应周期。
  4. 现场保存与上下文切换:CPU自动将当前指令的返回地址(CS:RIP)、标志寄存器(RFLAGS)压入内核栈,然后从IDT中查找中断向量对应的门描述符,加载新的CS:RIP(即中断服务例程入口地址)。
  5. 执行中断服务例程(ISR):CPU跳转到ISR执行。ISR通常分为上半部(Top Half,快速、不可阻塞)和下半部(Bottom Half,如Tasklet、Workqueue、Softirq,可延迟、可阻塞)。
  6. 中断返回(IRET):ISR执行完毕后,执行IRET指令,从内核栈恢复RIP、RFLAGS、CS等寄存器,CPU恢复执行被中断的用户态或内核态程序。

1.4 中断处理流程SVG架构图

下图展示了从硬件设备到CPU核心的完整中断处理流程,重点标注了中断控制器路由和CPU现场切换的关键节点。

中断处理流程架构图 中断处理流程架构图 硬件设备 (网卡/磁盘/定时器) 中断控制器 (APIC / MSI-X) CPU核心 (Core 0 / Core 1) 中断请求 路由/仲裁 IDT查找 中断描述符表 向量号 现场保存 压栈 RIP/RFLAGS ISR执行 上半部 / 下半部 IRET 返回 说明: • 中断控制器决定路由目标 • CPU自动完成现场保存 • ISR分上半部/下半部执行

1.5 中断向量与IDT

每个中断源都被分配一个唯一的中断向量号(Vector Number),范围0~255。Linux内核在x86_64架构上使用以下分配策略:

  • 0~31:保留给CPU异常(如#DE=0, #DB=1, #NMI=2, #BP=3, #PF=14)
  • 32~127:分配给设备中断(IRQ 0~223,通过IOAPIC或MSI-X映射)
  • 128:用于系统调用(int 0x80,兼容模式)
  • 129~255:保留给内核内部使用(如IPI、时钟中断、紧急中断)
性能陷阱:在传统PIC(8259A)模式下,所有设备中断共享一个中断向量,导致中断处理无法分发到不同CPU核心。MSI-X的核心优势之一就是为每个设备队列分配独立的向量号,从而实现多核负载均衡。

1.6 中断上下文与进程上下文

中断服务例程运行在中断上下文(Interrupt Context)中,与普通的进程上下文有本质区别:

属性 中断上下文 进程上下文
可睡眠 ❌ 不可睡眠(不能调用 schedule()) ✅ 可睡眠(可被调度器切换)
可被抢占 ❌ 不可被用户态抢占,但可被高优先级中断打断 ✅ 可被抢占(PREEMPT内核)
持有锁 只能使用 spinlock,不能使用 mutex 可使用 mutex、semaphore 等睡眠锁
访问用户态内存 ❌ 不能直接访问(current->mm 可能无效) ✅ 可通过 copy_from_user() 访问
执行时间要求 极短(微秒级),否则导致中断延迟增大 相对宽松(毫秒级甚至更长)
优化启示:中断上下文不可睡眠的特性决定了ISR必须快速完成。这正是MSI-X多向量中断的价值所在——通过将不同功能的中断分发到不同CPU核心,每个核心只需处理自己负责的向量,避免单核过载,从而降低中断延迟。