1. 中断基础概念

1.1 中断的定义

中断(Interrupt)是一种硬件或软件向处理器发送的异步信号,用于通知处理器发生了需要立即关注的事件。中断机制是现代操作系统实现多任务、实时响应和外设交互的核心基石。

核心要点:中断允许CPU在执行当前指令流时,被外部或内部事件“打断”,转去执行一个专门的中断服务程序(ISR, Interrupt Service Routine),处理完成后恢复原来的执行流。

中断按来源可分为两大类:

分类 来源 典型示例 特点
硬件中断 外部设备(网卡、磁盘、键盘) 网卡收到数据包、磁盘完成I/O 异步、随机、与CPU时钟无关
软件中断 CPU指令主动触发(INT指令) 系统调用(int 0x80)、异常处理 同步、由程序主动发起
异常 CPU内部检测到的错误或特殊状态 缺页异常、除零错误、段错误 同步、与当前指令执行直接相关
术语辨析:在Linux内核语境中,“中断”通常特指硬件中断,而“异常”和“软件中断”被归入“陷阱(Trap)”或“故障(Fault)”类别。x86架构下,系统调用通过 int 0x80 或 syscall 指令实现,属于软件中断的一种。

1.2 中断向量表(IVT/IDT)

中断向量表是处理器用来将中断号映射到对应中断服务程序入口地址的数据结构。在x86实模式下称为IVT(Interrupt Vector Table),在保护模式和长模式下称为IDT(Interrupt Descriptor Table)。

中断向量表(IDT)结构示意图 IDTR 基址寄存器 中断描述符表(IDT) 中断号 段选择子 偏移地址 类型/属性 0(除零) 0x0010 0xffff8100 陷阱门 3(断点) 0x0010 0xffff8200 陷阱门 14(缺页) 0x0010 0xffff8300 陷阱门 32(时钟) 0x0010 0xffff8400 中断门 33(键盘) 0x0010 0xffff8500 中断门 ⋮ 255 0x0010 0xffff8f00 中断门 IDT最多容纳256个描述符(0~255),每个描述符8字节,共2KB。中断号32~255由硬件设备使用。

在Linux内核中,IDT的初始化在 start_kernel() → trap_init() 和 early_irq_init() 中完成。每个中断描述符包含以下关键字段:

  • 段选择子(Segment Selector):指向GDT或LDT中的代码段描述符,用于确定中断服务程序运行的特权级。
  • 偏移地址(Offset):中断服务程序入口地址的低32位和高32位(x86_64),与段选择子共同构成完整的函数指针。
  • 类型/属性(Type/Attributes):标识描述符类型(中断门、陷阱门、任务门),以及DPL(Descriptor Privilege Level)等权限信息。
关键区别:中断门(Interrupt Gate)在执行ISR时会自动清除EFLAGS中的IF位(禁止嵌套中断),而陷阱门(Trap Gate)不会。Linux内核为硬件中断使用中断门,为异常和系统调用使用陷阱门。

1.3 中断控制器(APIC)的作用

中断控制器是连接外设与CPU的桥梁,负责接收来自多个设备的中断请求,进行优先级仲裁,并将中断向量号发送给CPU。现代x86系统使用高级可编程中断控制器(APIC, Advanced Programmable Interrupt Controller)体系。

APIC体系包含两个核心组件:

组件 位置 功能 关键寄存器
本地APIC(Local APIC) 集成在每个CPU核心内部 接收来自I/O APIC的中断消息、处理IPI(处理器间中断)、管理本地中断源(时钟、热敏) IRR(中断请求寄存器)、ISR(服务中寄存器)、ICR(中断命令寄存器)
I/O APIC 芯片组(南桥)内 收集外设的中断请求,通过系统总线将中断消息发送给指定CPU的本地APIC 重定向表(Redirection Table)、IOREDTBL
APIC中断路由架构图 外设设备 网卡(IRQ 18) 磁盘(IRQ 14) 键盘(IRQ 1) I/O APIC 重定向表(24项) 中断优先级仲裁 目标CPU选择 系统总线 CPU 0 本地APIC IRR / ISR 寄存器 中断向量接收 CPU 1 本地APIC IRR / ISR 寄存器 中断向量接收 I/O APIC通过重定向表将外设中断映射到指定CPU,支持中断负载均衡。本地APIC接收后设置IRR位,等待CPU响应。

1.4 中断处理流程

一个完整的中断处理流程从外设触发中断信号到CPU执行完ISR,涉及以下关键步骤:

  1. 中断触发:外设通过PCIe总线或专用中断线向I/O APIC发送电平或边沿信号。
  2. 中断仲裁:I/O APIC根据重定向表中的优先级设置,选择当前优先级最高的中断请求。
  3. 中断消息发送:I/O APIC通过系统总线向目标CPU的本地APIC发送包含中断向量号的中断消息。
  4. 本地APIC接收:目标CPU的本地APIC将中断向量号写入IRR(Interrupt Request Register)对应位,并向CPU核心发送中断信号。
  5. CPU响应:CPU在指令边界检查中断标志位(IF),若允许中断则保存当前上下文(CS、RIP、RFLAGS等寄存器压栈)。
  6. IDT查找:CPU以中断向量号为索引,从IDT中读取对应的中断描述符,获取ISR入口地址。
  7. ISR执行:CPU跳转到ISR执行中断处理逻辑。Linux内核将ISR分为上半部(快速处理)和下半部(推迟处理)。
  8. 中断返回:ISR执行 iretq 指令恢复上下文,CPU继续执行被中断的程序。
性能关键点:中断处理过程中,CPU需要保存和恢复寄存器状态,这会引入上下文切换开销。对于高速网络设备(如10GbE/40GbE网卡),每秒可能产生数十万次中断,纯中断模式会导致CPU被中断处理完全占据——这正是NAPI轮询机制要解决的核心问题。

1.5 中断亲和性与负载均衡

Linux内核通过 /proc/irq/{IRQ_NUM}/smp_affinity 接口控制中断在多个CPU之间的分配。每个中断源可以绑定到特定的CPU核心或核心组,实现中断负载均衡。

# 查看中断18(网卡)的当前亲和性掩码
$ cat /proc/irq/18/smp_affinity
00000000,00000000,00000000,00000001

# 将中断18绑定到CPU 0和CPU 2(掩码=0x5)
$ echo 5 > /proc/irq/18/smp_affinity

# 查看中断分布统计
$ cat /proc/interrupts | grep eth0
 18:  12345678  23456789  34567890  45678901  IO-APIC  18-eth0
特性 传统PIC(8259A) APIC(现代系统)
最大中断源数 15(级联后) I/O APIC支持24~120个,理论上限255
CPU支持 单CPU 多CPU,支持中断亲和性设置
中断路由 固定路由到BSP 可编程路由到任意CPU或CPU组
优先级管理 固定优先级(IRQ0最高) 可编程优先级,支持旋转优先级
IPI支持 不支持 支持处理器间中断(TLB刷新、函数调用等)
实践建议:在NUMA架构下,应将设备中断绑定到与设备所在PCIe插槽同一NUMA节点的CPU核心上,以降低跨节点内存访问延迟。使用 irqbalance 守护进程可自动优化中断分配。