跳到正文

中断、异常与设备模型

本文性质声明:本机无 Linux 环境,全部内容未实测,为原理级框架。站内对照实测:os-what-kernel-does(陷入成本 82.4ns、系统调用的 24 字节)、os-scheduling(Windows 优先级实测)、os-io-stack(IO 栈路径)。所有机制以你内核版本的文档为准。

一、中断 vs 异常:同步与异步的分野

CPU 遇到”计划外的事”只有两种来源:

中断(interrupt)异常(exception)
来源外部硬件(网卡收到包、定时器到点)指令执行本身(除零、缺页、非法指令)
时序异步——与当前指令无关,随时来同步——执行到这条指令必发生
例子键盘、磁盘完成、时钟 tick缺页中断、除零、断点、系统调用入口

系统调用走的是异常路径(syscall 指令故意触发一个”异常”进内核)——本站 os-what-kernel-does 实测过这条路径的成本:本机一次陷入 82.4 纳秒、指令本体 24 字节。

中断的核心矛盾:硬件事件随时到,而 CPU 同一时刻只能干一件事——中断处理函数(ISR)抢占了当前执行流。这决定了它必须快:ISR 里睡着,整个系统的响应就停了。

二、上半部 / 下半部:为什么必须拆

网卡收到包时,ISR 要做的事有两类:硬件必须立刻响应的(读状态寄存器清中断标志、把包从网卡 FIFO 拷进内存——不拷完新包会覆盖)和可以延后的(解析协议栈、递给 socket 缓冲区、叫醒等待的进程)。前者是上半部(top half),后者是下半部(bottom half)。

拆分的三条理由:

  1. 上半部跑在中断上下文:不能睡眠(睡眠意味着调度,而中断上下文没有可调度的进程背景——让它睡 = 内核bug)、不能拿可能被持有的锁(死锁风险)、要尽量短(同类中断被屏蔽的时间就是丢事件的窗口)。
  2. 中断被屏蔽的时长 = 系统延迟:一个 1ms 的 ISR 意味着定时器精度、其他设备的响应全部劣化 1ms。
  3. 下半部把工作带回进程上下文——能睡眠、能拿锁、能被调度。

Linux 的下半部演进:软中断(softirq)(编译期固定的几类:网络收包 NET_RX_SOFTIRQ、定时器 TIMER_SOFTIRQ、调度 SCHED_SOFTIRQ——同类型软中断在多个 CPU 上并发跑,性能优先,编写最难)→ tasklet(建立在软中断上,同一 tasklet 不并发——比软中断好写,已半废弃)→ 工作队列(workqueue)(带回进程上下文,能睡眠——驱动开发默认选它)。选择口诀:要快要并发用软中断(网络栈),要省事用 workqueue(普通驱动),tasklet 别在新代码用。

三、驱动分层与设备树

驱动不是一坨代码,是栈:

用户程序 → VFS/子系统(网络栈、块层)→ 核心驱动层 → 总线驱动(PCI/USB/platform)→ 硬件

总线驱动层统一做”枚举设备、匹配驱动、提供 DMA/中断抽象”——具体驱动只实现”这个芯片怎么玩”。平台总线(platform bus) 是给没有自动枚举总线的设备(SoC 上的串口、I2C 外设)用的:设备信息从设备树(Device Tree)来。

**设备树(DTS)**是描述”这块板子上有什么硬件”的数据文件(不是代码):soc { serial@10000000 { interrupts = <0 1 4>; clocks = <&uart0>; }; }。内核启动时解析它,实例化出 platform 设备。改硬件配置(换个中断号)改 DTS 不改内核——嵌入式开发”改设备树”比”改驱动”频率高得多(本站 emb-startup 会从启动流程讲它怎么被用)。

四、中断亲和、亲和与风暴

中断亲和(IRQ affinity):cat /proc/irq/25/smp_affinity 决定该中断由哪个 CPU 处理。默认策略让内核自动分摊;高吞吐场景手动绑:网卡中断绑到固定几个核、应用线程避开这几个核——数据在哪 CPU 上被处理,缓存就热在哪(本站 os-scheduling 量过 Windows 侧优先级,dbg-data-layout 量过缓存友好的量级)。

中断风暴(interrupt storm):中断来得比处理得快——现象是 CPU 全花在 ISR 里(top 看 %softirq/si 高)、系统假死。治理三板斧:

  1. 关中断聚合(NAPI):网卡高频收包时关中断、改轮询,包处理完再开——用轮询换中断, Linux 网络栈的标准手段。
  2. 节流:驱动里发现中断频率异常(如每秒上万次相同中断)主动屏蔽并告警——坏硬件的自我保护。
  3. 找出源头:watch -n1 cat /proc/interrupts 看哪个中断计数在疯涨;%softirq 高但 /proc/interrupts 平稳 = 软 intra-softirq 层的问题(如内核协议栈处理不过来)。

五、排障索引

症状入口
系统周期性卡顿几十毫秒ISR 太长或下半部堆积;/proc/interrupts 看计数节奏
一个核 100% 其他空闲软中断/硬中断亲和集中;ksoftirqd 核上的负载
网卡吞吐上不去NAPI/中断聚合没生效;队列深度;亲和绑核
唤醒的延迟不稳中断亲和 + CPU 休眠状态(cpuidle 深度);cyclictest 量抖动
驱动 probe 失败设备树/ACPI 描述与硬件不符;dmesg 的 probe deferral

六、未实测清单

  • 本文所有内核机制——无 Linux 环境,未测。
  • ISR/软中断的耗时——未测(Windows 侧对应物:DPC/IST,未涉及)。
  • NAPI 轮询行为——未测。
  • 设备树的解析细节——未测。
  • 中断亲和的实际收益——未测(原理引用 dbg-data-layout 的缓存实测)。