第4章 中断

1 处理器探测异常

  • fault:可以被纠正,并不失连贯的执行;比如缺页异常
  • trap:发生后没有必要纠正和继续执行,调试时使用,可以认为是断点
  • abort:发生严重的错误,只能强制终止受影响的进程;比如assert?

 

 

2 硬件连接

设备 <== IRQ ==> 可编程中断控制器PIC <== INTR引脚 ==> CPU;

不同CPU之间也可以发送处理器间中断,称为IPI。

 

 

3 中断和异常

中断或异常会引起一个内核控制路径,也就是说中断/异常发生时,以内核态保存当前进程的寄存器数据,并执行中断处理函数。

 

3.1 中断嵌套

Linux内核之前允许中断嵌套,目前不允许中断嵌套 —— 通过在硬件中断处理函数前屏蔽中断实现。

 

3.2 缺页异常和中断

因为异常是在内核态执行,内核态只会引起缺页异常,不会引起其他异常(除非内核有BUG);而缺页异常从不进一步引起异常,因此内核最多有两层异常嵌套。

另外,缺页异常发生时,内核会挂起当前进程,进行进程切换

因此:

  • 中断处理程序可以抢占异常处理程序
  • 中断处理程序执行时不可以进行进程切换,所以中断中不可以执行导致异常的操作(比如申请内存导致缺页异常),也不能休眠

如果在中断处理函数里发生了缺页中断会怎样?

缺页异常指的是访问的虚拟内存没有映射到物理内存中,不是申请内存的时候内存不足,因此在中断中如何避免缺页异常呢?

通义千问给出的答案很好:

  • 避免访问用户空间:内核空间始终映射,因此不会发生缺页;如果确实需要访问用户空间,应该提前copy_from_user()
  • 优化中断程序:中断处理程序要简洁高效,并减少内存分配和页面访问
  • 将当前进程的PF_NOFREEZE标志置位,防止内存回收触发缺页异常

 

 

4 异常处理

异常发生时,内核向引起异常的进程发送一个“异常信号”;

进程如果设置了该异常信号的处理程序,则进行处理恢复;如果没有设置则终止运行。

 

 

5 中断处理

5.1 区别IRQ和ISR

  • 几个设备可以共享一个IRQ线
  • 每个设备都有自己的ISR(interrupt service routine,中断服务例程)

 

5.2 IRQ类型

  • IRQ共享:产生IRQ时,挂在IRQ上每个设备的ISR都要执行,在ISR内部判断并进行中断处理 —— 这就是设备ISR中先判断irq state的原因
  • IRQ动态分配:在最后一刻才让IRQ与设备驱动程序关联(分时复用);比如用户访问磁盘时才会使能磁盘IRQ响应

 

5.3 I/O中断处理程序的基本操作

  1. 禁用IRQ中断响应
  2. 在内核态堆栈中保存IRQ的值和寄存器的内容
  3. 执行共享IRQ的多个ISR
  4. 跳到ret_from_intr()并结束中断处理程序

 

 

6 软中断、tasklet、工作队列

6.1 软中断 softirq

规则

  • 软中断支持同时在多个CPU上执行,需要设计为可重入函数,需要自旋锁保护
  • 不能被自己打断(单个CPU上不能嵌套),只能被硬件中断打断
  • 目前Linux系统最多支持32个软中断,系统已经定义使用了10个,剩下的用户可以自己指定,一般来说系统提供的软中断已经够我们使用了

执行时机

  • 触发软中断后(raise_softirq())
  • 硬中断退出时
  • 任何调用local_bh_enable()打开本地软中断的时候

 

6.2 tasklet

  • 基于软中断实现,是软中断的一种
  • 由内核实现并控制,只需要知道相同类型的tasklet总是顺序执行的,不会有多个CPU执行相同类型的tasklet——这一点不同于软中断,因此tasklet执行函数也不用设计为可重入的
  • 简单好用,IO驱动程序中实现可延迟函数的首选方法
  • 软中断和tasklet是运行于中断上下文的,因此在执行过程中不能休眠

 

6.3 工作队列 work queue

  • 将延后工作交由内核线程来处理
  • 工作队列允许重新调度甚至睡眠,这是与软中断根本的不同

 

6.4 选择

需要切换进程(比如休眠) =》工作队列;

性能至上、可重入 =》软中断;

其他 =》 优先选择tasklet

 

 

7 内核控制路径的几种情况

7.1 单个CPU上交错(嵌套)执行

  • 条件最为严苛,单个CPU上交错执行相当于多个CPU同时执行,而且还需要同步CPU独有的变量!
  • 需要写成可重入函数
  • 所有的数据访问都需要加锁(保证同步)
  • 软中断、tasklet和工作队列都不是

 

7.2 会在多个CPU上同时执行,但是不会在单个CPU上交错执行

  • 也需要写成可重入函数
  • 属于CPU独有的变量不需要加锁,全局变量需要加锁同步
  • 软中断是这样!

 

7.3 会在多个CPU上执行,但是不会同时被多个CPU执行,更不会在单个CPU上交错执行

  • 这种机制由内核保证,也就是tasklet的实现
  • 不会在多个CPU上同时执行,那就是顺序执行了
  • 不必是可重入函数

 

posted @   moonのsun  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示