Skip to content

第一百三十五章:中断之道

合道期

涉及内核源码:

林小源正在设备山脉的半山腰休息,忽然一声尖锐的啸声划破天空。

他猛地抬头,只见一道紫色的闪电从远处的一块巨石上迸发而出,直冲云霄。闪电在空中炸开,化作一道道电弧,向四面八方扩散。

"那是什么?!"林小源惊呼。

"中断。"守山老者平静地说,仿佛早已司空见惯。

话音未落,天空中出现了一个巨大的身影——一个身穿紫色铠甲的武神,手持一柄闪电长枪。他的铠甲上刻着一个数字:IRQ 10

"我是中断控制器。"武神的声音如雷鸣,"硬件设备需要 attention 时,会通过我向 CPU 发出信号。CPU 收到信号后,暂停当前的工作,跳转到中断处理函数。"

武神挥动长枪,一道闪电击中了远处的一块石头——那是一块网卡设备。石头立刻亮了起来,发出嗡嗡的震动声。

"看到没有?"武神说,"网卡收到了数据包,它需要 CPU 来处理。于是它触发中断信号,通过中断控制器传给我,我再传给 CPU。整个过程不到一微秒。"

林小源感觉到脚下的地面微微震动——那是 CPU 响应中断时的"现场切换"。

c
/*
 * 中断的类型:
 *
 * 1. 硬中断
 *    硬件触发
 *    通过中断控制器传递给 CPU
 *    例: 网卡收到数据、磁盘完成 I/O
 *
 * 2. 软中断
 *    软件触发
 *    在中断上下文中执行
 *    例: 网络收包处理、定时器
 *
 * 中断处理流程:
 *   硬件触发中断
 *     ↓
 *   中断控制器传递给 CPU
 *     ↓
 *   CPU 保存现场
 *     ↓
 *   跳转到中断处理函数
 *     ↓
 *   执行中断处理
 *     ↓
 *   恢复现场
 *
 * 注册中断:
 *   request_irq(irq, handler, flags, name, dev_id)
 */

printf("=== 中断 — 硬件的呼唤 ===\n\n");

printf("中断的类型:\n\n");

printf("1. 硬中断:\n");
printf("   硬件触发\n");
printf("   通过中断控制器传递给 CPU\n");
printf("   例: 网卡收到数据、磁盘完成 I/O\n\n");

printf("2. 软中断:\n");
printf("   软件触发\n");
printf("   在中断上下文中执行\n");
printf("   例: 网络收包处理、定时器\n\n");

printf("--- 中断处理流程 ---\n");
printf("硬件触发中断\n");
printf("  ↓\n");
printf("中断控制器传递给 CPU\n");
printf("  ↓\n");
printf("CPU 保存现场\n");
printf("  ↓\n");
printf("跳转到中断处理函数\n");
printf("  ↓\n");
printf("执行中断处理\n");
printf("  ↓\n");
printf("恢复现场\n\n");

printf("--- 注册中断 ---\n");
printf("request_irq(irq, handler, flags, name, dev)\n");
printf("  irq: 中断号\n");
printf("  handler: 中断处理函数\n");
printf("  flags: IRQF_SHARED 等\n");
printf("  name: 设备名\n");
printf("  dev: 设备 ID\n\n");

printf("--- 中断处理函数 ---\n");
printf("irqreturn_t handler(int irq, void *dev) {\n");
printf("  // 读取设备状态\n");
printf("  // 处理中断事件\n");
printf("  // 清除中断标志\n");
printf("  return IRQ_HANDLED;\n");
printf("}\n\n");

printf("--- 中断的约束 ---\n");
printf("中断处理函数中不能:\n");
printf("  休眠\n");
printf("  获取可能休眠的锁\n");
printf("  做耗时的操作\n");

"中断处理听起来很简单——设备叫一声,CPU 去处理一下。有什么难的?"林小源说。

武神的面色突然沉了下来。他把长枪往地上一顿,周围的空气都凝固了。

"难在约束。"武神压低声音,"中断处理函数在'中断上下文'中执行。你知道这意味着什么吗?"

林小源摇摇头。

"意味着你不能休眠。"武神一字一顿地说,"不能调用任何可能让当前执行流休眠的函数——不能获取 mutex,不能分配大块内存,不能做任何可能阻塞的操作。因为中断处理期间,CPU 的状态是特殊的——没有进程上下文,没有调度器保护。如果你休眠了,就没有人来唤醒你。"

林小源的脊背发凉。

"还不止这些。"武神继续说,"中断处理期间,其他中断可能被屏蔽。你每多花一微秒,就多一微秒的中断延迟。如果你的处理函数耗时太长,后面的中断就会丢失——设备的数据包收不到、磁盘的完成通知听不到。"

"所以中断处理要尽可能快。"林小源说。

"对。"武神点头,"读一下设备状态,清除中断标志,把数据拷贝到安全的地方——然后立刻返回。真正耗时的处理,留给下半部。"

"如果两个设备共用一个中断号呢?"林小源忽然想到一个问题。

武神的表情变得意味深长。他指向远处的两块石头——一块是网卡,一块是声卡。两块石头之间连着一根细细的线,线上刻着同一个数字:IRQ 11

"共享中断。"武神说,"有时候中断号不够用,多个设备共享同一个中断号。当 IRQ 11 触发时,内核不知道是哪个设备发的——可能是网卡,可能是声卡,也可能两个都发了。"

"那怎么办?"

"每个中断处理函数都要检查——'是我的设备触发的吗?'"武神说,"读设备的状态寄存器,看中断标志位。如果是你的设备,处理它,返回 。如果不是,返回 ,让下一个处理函数来检查。"

林小源看着那两块共享中断号的石头,心想:共享听起来方便,但每次中断都要做额外的判断,性能会有所损耗。而且如果其中一个驱动有 bug,不清除自己的中断标志,就会反复触发中断——这就叫中断风暴,整个系统都会被拖垮。

"你想到点子上了。"武神仿佛看穿了他的心思,"共享中断是方便,但代价是信任——你必须相信跟你共享中断号的驱动是靠谱的。"


道藏笔记

内核启示

中断是硬件通知 CPU 的机制。

中断类型:

  • 硬中断 — 硬件触发
  • 软中断 — 软件触发

中断处理流程:

  • 硬件触发 → 中断控制器 → CPU 保存现场 → 执行处理 → 恢复现场

中断的约束:

  • 不能休眠
  • 不能获取可能休眠的锁
  • 应该尽可能快

中断是"呼唤"——让 CPU 响应硬件事件。


破关试炼

中断之试

中断处理函数确认自己已经处理完该中断时,本章返回的状态值是什么?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道