1. 中断概念回顾:什么是中断、中断向量表、中断上下文与进程上下文

中断(Interrupt)是硬件或软件向处理器发出的异步事件信号,用于通知处理器有高优先级事件需要立即处理。中断机制是操作系统响应外部设备、处理异常和实现多任务抢占的核心基础。理解中断的基本概念,是掌握 Linux 内核中断底半部与工作队列调度的前提。

核心要点:中断允许 CPU 在执行当前指令流时,被外部或内部事件打断,转而执行一个预先定义的中断服务程序(ISR),处理完成后恢复原来的执行流。这种机制避免了 CPU 轮询等待,大幅提高了系统实时性和效率。

1.1 中断的定义与分类

中断根据触发源和特性,可以分为以下几类:

分类 触发源 特点 典型示例
硬件中断 外部设备(如网卡、磁盘、键盘) 异步、随机发生、与 CPU 时钟无关 网卡收到数据包、磁盘完成读写
软件中断 CPU 指令(如 int 0x80、系统调用) 同步、由程序主动触发 Linux 系统调用、异常处理
异常 CPU 内部错误或特殊条件 同步、与当前指令执行直接相关 除零错误、缺页异常、非法指令
嵌入式开发提示:在嵌入式 Linux 系统中,硬件中断是最常见的类型。GPIO 电平变化、定时器溢出、UART 接收数据等都会触发硬件中断。正确配置中断优先级和响应时间,是嵌入式实时系统设计的关键。

1.2 中断向量表(Interrupt Vector Table, IVT)

中断向量表是一张存储在内存固定地址的表格,每个表项对应一个中断号,保存着该中断对应的中断服务程序(ISR)入口地址。当 CPU 收到中断信号时,硬件自动根据中断号查找 IVT,跳转到对应的 ISR 执行。

在 x86 架构中,IVT 位于内存地址 0x0000 ~ 0x03FF(共 1024 字节),每个表项占 4 字节(段地址 + 偏移量),最多支持 256 个中断向量。在 ARM 架构中,中断向量表通常位于 0x00000000 或 0xFFFF0000,每个表项占 4 字节,支持异常向量和中断向量。

注意:现代 Linux 内核使用中断描述符表(IDT)替代了传统的 IVT。IDT 在保护模式下使用,每个表项包含更多控制信息(如 DPL、段选择子、门类型等),支持中断门、陷阱门和任务门三种类型。但 IVT 的概念仍然是理解中断机制的基础。
中断向量表(IVT)结构示意图 CPU 中断信号 中断控制器 中断号 n 中断向量表(IVT) 向量 0 ISR_0 入口地址 向量 1 ISR_1 入口地址 向量 2 ISR_2 入口地址 ... ... 向量 255 ISR_255 入口地址 跳转 中断服务程序 ISR 返回原执行流 说明:CPU 收到中断信号后,中断控制器提供中断号 n,CPU 根据 n 在 IVT 中查找对应的 ISR 入口地址并跳转执行。

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

Linux 内核将 CPU 的执行环境分为两种上下文:中断上下文(Interrupt Context)和进程上下文(Process Context)。理解两者的区别,是正确编写中断处理程序和使用工作队列的基础。

对比维度 中断上下文 进程上下文
执行环境 运行在中断服务程序(ISR)或底半部(如 tasklet、软中断)中 运行在用户进程或内核线程中
可睡眠 ❌ 不可睡眠(不能调用可能导致阻塞的函数) ✅ 可以睡眠(如等待 I/O、获取信号量)
可被抢占 通常不可被其他中断抢占(取决于中断优先级设置) 可以被调度器抢占
访问用户空间 ❌ 不能访问用户空间内存 ✅ 可以访问用户空间内存
持有锁 只能使用自旋锁(spinlock),不能使用信号量 可以使用信号量、互斥锁等
当前进程指针 current 宏指向被中断的进程,但不代表中断上下文所属 current 宏指向当前运行的进程
关键规则:中断上下文不能睡眠!这是 Linux 内核编程中最重要的一条规则。如果在中断上下文中调用了 schedule()、wait_event()、mutex_lock() 等可能导致阻塞的函数,系统将发生内核崩溃(kernel panic)。这也是为什么我们需要将耗时操作推迟到进程上下文中执行的原因——这正是工作队列(workqueue)的核心价值。

1.4 中断处理流程概览

Linux 内核的中断处理分为两个阶段:

  1. 顶半部(Top Half):在中断上下文中立即执行,完成最紧急的硬件操作(如清除中断标志、读取硬件寄存器),要求执行时间尽可能短。
  2. 底半部(Bottom Half):将耗时或非紧急的处理推迟到稍后执行,可以在中断上下文(如 tasklet、软中断)或进程上下文(如工作队列)中执行。
Linux 内核中断处理流程(顶半部 + 底半部) 硬件设备 中断信号 顶半部 (中断上下文) 立即执行,快速处理 调度底半部 底半部 (中断上下文) tasklet / 软中断 或 工作队列 (进程上下文) 可睡眠,可调度 恢复被中断的进程 说明:顶半部执行紧急硬件操作后调度底半部,底半部在适当时间执行剩余处理,最后恢复被中断的进程。

1.5 中断上下文与进程上下文的切换代价

中断上下文与进程上下文之间的切换涉及以下开销:

  • 寄存器保存与恢复:进入中断上下文时,CPU 自动保存当前进程的寄存器状态(如 PC、SP、PSW 等),退出时恢复。
  • 栈切换:中断上下文使用内核栈(每个进程一个内核栈),进程上下文使用用户栈或内核栈。
  • TLB/缓存影响:频繁的中断可能导致 TLB 和缓存失效,影响系统性能。
  • 中断嵌套:高优先级中断可以打断低优先级中断,增加上下文切换的复杂度。
性能建议:在嵌入式系统中,中断响应时间直接影响实时性。建议将顶半部的执行时间控制在微秒级别,底半部控制在毫秒级别。对于需要长时间处理的任务(如网络协议栈处理、磁盘 I/O 完成处理),应使用工作队列在进程上下文中执行。

1.6 本章小结

中断是 Linux 内核处理异步事件的核心机制。通过中断向量表,CPU 能够快速定位并执行对应的中断服务程序。中断上下文与进程上下文的严格区分,决定了我们在编写中断处理代码时必须遵守的规则:中断上下文不能睡眠、不能访问用户空间、只能使用自旋锁。理解这些基础概念,为后续学习中断底半部机制(软中断、tasklet)和工作队列调度奠定了坚实的理论基础。