20260110 - Linux 驱动开发学习笔记:上下文、中断与休眠

📚 Linux 驱动核心笔记:上下文、中断与休眠

一、 核心概念对比:进程上下文 vs 中断上下文

要理解为什么不能在中断处理函数中里调用休眠函数让出CPU,首先必须搞清楚代码是在什么环境(上下文)下运行的

1. 进程上下文 (Process Context)

  • 定义 :当用户程序(APP)通过系统调用(如 open, read, write, ioctl)陷入内核态时,内核正在代表这个 APP 执行代码。
  • 特点
    • 有身份 :拥有对应的 task_struct(进程控制块),记录了 PID、打开的文件、内存页表等信息。
    • 有行李 :因为有 task_struct,它可以保存当前的运行状态(寄存器、堆栈)。
    • 可休眠:因为有地方保存状态,内核可以把它挂起(Sleep),把 CPU 让给别人,稍后再恢复它。
  • 场景 :应用进入到内核态后,一般会调用驱动里的 xxx_read, xxx_write, xxx_open 函数,而这些函数通常都运行在进程上下文。

2. 中断上下文 (Interrupt Context)

  • 定义:当硬件触发信号(如按键按下、网卡收包),CPU 强行打断当前正在运行的任务,跳转到中断处理函数(ISR)执行。
  • 特点
    • 无身份 :中断不是进程,它没有自己的 task_struct。它是一个"不速之客",借用当前正在运行的那个倒霉进程的内核栈来运行。
    • 无行李:它没有地方保存"暂停时的状态"以便被调度器管理。
    • 不可休眠:这是铁律。
  • 场景 :驱动里通过 request_irq 注册的 handler 函数(如 gpio_key_isr)。

3. 直观对比表

特性 进程上下文 (Process Context) 中断上下文 (Interrupt Context)
代表人物 APP (通过系统调用进入内核) 硬件中断 (ISR)
持有凭证 task_struct (身份证) 无 (借用别人的)
能否休眠 (msleep, copy_to_user) 绝对不能
能否被调度 受调度器管理 优先级极高,不可被调度器抢占
执行目标 服务于特定的 APP 请求 响应硬件紧急事件

二、 深度解析:为什么中断里不能休眠?

1. 根本原因:找不到回家的路

休眠的本质是**"让出 CPU"并触发"调度器"**。

  • 过程 :当进程休眠时,内核把它的状态存入 task_struct,然后切到别的进程。
  • 中断的困境 :中断没有 task_struct
    • 如果在中断里调用 msleep,调度器会试图把"当前状态"保存起来。但"当前状态",即上下文,属于被中断的那个无辜进程,而不是中断本身。
    • 如果真的切换走了,调度器再也找不到这个中断处理函数了(因为它不在调度队列里)。中断一旦挂起,硬件就会一直等待,或者数据丢失,系统逻辑彻底崩塌。

2. 内核的反应:Kernel Panic

Linux 内核设计有检测机制。如果在中断上下文中检测到调度行为(如调用了 msleepschedule),内核会立即抛出致命错误:

Panic: scheduling while atomic

(在原子上下文中尝试调度)

这意味着系统崩溃,通常会死机或重启。


三、中断中可以延时吗?

答案:可以,但不能使CPU休眠。

1. msleep 的机制

  • msleep 不管延时多短(哪怕 1 纳秒),它的实现逻辑都是:
    1. 设置定时器。
    2. 调用 schedule() 让出 CPU
    3. 进程进入睡眠队列。
  • 只要涉及 "让出 CPU""调用 schedule()",在中断里就是死罪。

2. 如果非要延时怎么办?

在中断中如果必须延时(例如复位硬件需要维持 5us 低电平),只能使用 "忙等待" 函数:

  • udelay(us)mdelay(ms)
  • 原理 :CPU 在原地空转(执行死循环指令),不让出 CPU
  • 代价:这期间 CPU 100% 占用,不能处理其他任务。所以只能用于极短时间的延时(通常微秒级)。

四、 扩展名词解释 (Glossary)

为了更好地阅读内核代码,以下是几个必须掌握的专业术语:

1. 原子上下文 (Atomic Context)

  • 解释 :指一段必须连续执行、不可被分割、不可被挂起的代码区域。
  • 包含
    1. 所有中断处理程序(硬中断、软中断)。
    2. 持有 自旋锁 (Spinlock) 的代码段。
  • 规则 :在原子上下文中,禁止任何可能导致休眠或调度的操作

2. 抢占 (Preemption)

  • 解释:高优先级的任务强行打断低优先级的任务,夺取 CPU 使用权。
  • 内核抢占 :Linux 是可抢占内核,意味着即便驱动程序在内核态跑着(进程上下文),如果有更高优先级的进程醒了,也可以打断它。但在中断上下文中,通常禁止抢占。

3. 用户空间与内核空间 (User Space vs Kernel Space)

  • 用户空间:APP 运行的地方,权限受限,不能直接访问硬件寄存器。
  • 内核空间:操作系统内核和驱动运行的地方,拥有最高权限。
  • copy_to_user / copy_from_user :这是两界之间的桥梁。
    • 注意 :这两个函数通过虚拟内存访问用户数据,可能会缺页异常(Page Fault)导致休眠。因此,这两个函数也不能在中断里用!

4. 忙等待 (Busy Wait)

  • 解释:CPU 不去休息,而是通过死循环来消磨时间。
  • 比喻:相当于你盯着微波炉倒计时(忙等待),而不是定个闹钟去睡觉(休眠)。
  • 对应函数ndelay, udelay, mdelay
相关推荐
linweidong8 小时前
嵌入式电机:如何在低速和高负载状态下保持FOC(Field-Oriented Control)算法的电流控制稳定?
stm32·单片机·算法
知南x10 小时前
【STM32MP157 视频监控项目】(2) 移植 Nginx
stm32·nginx·音视频
Zeku13 小时前
20260110 - Linux驱动学习笔记:环形缓冲区与按键防丢失
stm32·freertos·linux驱动开发·linux应用开发
youcans_13 小时前
【动手学STM32G4】(8)STM32G431之 DAC进阶
stm32·单片机·嵌入式硬件·dma·定时器
Zeku13 小时前
20260111 - Linux驱动学习笔记:异步通知
笔记·stm32·freertos·linux驱动开发·linux应用开发
TEC_INO14 小时前
STM32_9:I2C_DHT11_OLED项目
stm32·单片机·嵌入式硬件
__万波__14 小时前
STM32基于HAL 库开发包创建新的工程-编译-烧录
stm32·单片机·嵌入式硬件
曾浩轩14 小时前
跟着江协科技学STM32之4-5OLED模块教程OLED显示原理
科技·stm32·单片机·嵌入式硬件·学习
BreezeJuvenile15 小时前
ADC_案例练习:独立模式多通道采集
stm32·单片机·adc·多通道采集·dma辅助