Linux 系统中断是如何处理的?

小杰同学_4622

小杰同学_4622

2026-01-30

297人浏览

原创

CPU在当前指令执行完后立即暂停任务,硬件自动压入PC、CPSR/RIP/RFLAGS等寄存器到栈;随后经硬件向量跳转、中断控制器仲裁、内核asm_do_IRQ()三层调度才进入handler。

linux 系统中断是如何处理的?

中断触发后,CPU 怎么第一时间“停下手头活”?

硬件中断信号(比如网卡收到包、键盘按键)到达 CPU 的 INTR 引脚后,CPU 在当前指令执行完的边界立即暂停用户态或内核态任务,自动压入 PC、CPSR(ARM)或 RIP/RFLAGS(x86_64)等关键寄存器到当前栈——这一步完全由硬件完成,不依赖内核代码。你写驱动时看不到它,但它是整个中断流程不可绕过的起点。

常见误区是以为“中断一来就跳进你的 irq_handler_t”,其实中间隔着至少三层:硬件向量跳转 → 中断控制器(如 GIC 或 APIC)仲裁 → 内核通用入口 asm_do_IRQ()。如果你在 /proc/interrupts 里看到某 IRQ 计数不动,大概率是硬件没发信号,或者中断控制器配置漏了使能位(比如 GICD_CTLR 寄存器没置位)。

request_irq() 注册的是顶半部,但它到底干了什么?

调用 request_irq() 不是把函数直接塞进硬件,而是把你的处理函数挂到对应 irq_desc[irq] 结构体的 action 链表上,并让内核在该 IRQ 触发时调用 handle_irq() —— 这个函数再遍历 action 链表,逐个执行注册的 handler。所以多个驱动可以共享一个 IRQ(如 PCI 设备),只要每个 handler 开头都检查自己设备的中断状态寄存器是否真被触发。

  • 必须用 IRQF_SHARED 标志才能和别人共用 IRQ,否则 request_irq() 直接失败
  • handler 函数运行在中断上下文,不能调用 sleep()、copy_to_user()、mutex_lock() 等可能阻塞的函数
  • 返回值只能是 IRQ_NONE(不是我的中断)、IRQ_HANDLED(我处理了)、IRQ_WAKE_THREAD(交给线程化底半部)

为什么 ISR 里不能做耗时操作?底半部怎么选?

顶半部执行时,同 IRQ 会被自动屏蔽(disable_irq_nosync() 效果),如果在里面解析完整 TCP 包、写磁盘、分配大内存,其他设备(比如鼠标、定时器)就会卡住——你拖动窗口延迟、音频断续,根源可能就在这几行代码里。

Obsidian (Linux)
Obsidian (Linux)

操作 Obsidian 库(纯 Markdown 笔记),并通过 notesmd-cli 实现自动化。

下载

Linux 提供三类底半部机制,选错会影响实时性或吞吐:

  • softirq:内核编译时静态分配,高优先级、无锁、可重入,适合网络协议栈(NET_TX_SOFTIRQ)等极致性能场景,但必须用 open_softirq() 预注册,驱动一般不用
  • tasklet:基于 softirq 封装,单 CPU 串行执行,简单安全,适合大多数驱动(如 USB 主机控制器),但已标记为 legacy,新驱动建议避开
  • 线程化中断(IRQF_ONESHOT | IRQF_TRIGGER_* + request_threaded_irq()):把耗时部分放进内核线程,可调度、可睡眠、可使用全部内核 API,现代驱动首选

/proc/interrupts 和 cat /sys/firmware/devicetree/base/interrupt-controller@.../interrupts 对不上怎么办?

这是嵌入式开发最常踩的坑:设备树里写的 interrupts = ,对应的是 GIC SPI 中断号 23,但 /proc/interrupts 显示的是 Linux 全局 IRQ 编号(通常是 GIC 基地址 + 23)。如果你用 request_irq(23, ...) 肯定失败——得查 gic_irq_domain_translate() 或直接看启动日志里 “GICv2: using LPIs, GICD_BASE=0x...” 后推算,或者更稳妥:用 platform_get_irq() 从设备结构体里取,它已帮你做了映射。

另一个隐藏陷阱:某些 SoC(如 i.MX6ULL)的 GPIO 中断需要先调用 gpio_to_irq() 转换,而这个转换依赖 pin controller driver 是否已 probe 完成——如果驱动 initcall 顺序不对,gpio_to_irq() 可能返回 -EINVAL。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

linux

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

5114

18

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

2025.07.04

5271

25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

6447

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2688

6

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4558

6

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

2023.06.21

4350

4

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

2023.06.29

3673

10

linux find
linux find

find是linux命令,它将档案系统内符合 expression 的档案列出来。可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合,只有完全相符的才会被列出来。find根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部分为 path,之后的是 expression。还有指DOS 命令 find,Excel 函数 find等。本站专题提供linux find相关教程文章,还有相关

2023.06.30

2933

5

linux修改文件名
linux修改文件名

本专题为大家提供linux修改文件名相关的文章,这些文章可以帮助用户快速轻松地完成文件名的修改工作,大家可以免费体验。

2023.07.05

7230

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

Buffalo框架快速入门指南
Buffalo框架快速入门指南

共0课时 | 0人学习

Valgrind支持平台说明
Valgrind支持平台说明

共0课时 | 0人学习