【精通内核】Linux 内核中断控制原理源码解析
前言
📫作者简介:小明java问道之路,专注于研究计算机底层/Java/Liunx 内核,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计📫
🏆 InfoQ 签约博主、CSDN 专家博主/Java 领域优质创作者/CSDN 内容合伙人、阿里云专家/签约博主、华为云专家、51CTO 专家/TOP 红人 🏆
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
本文导读
CPU 对于任务切换是通过时钟中断来控制的,只要我们将中断屏蔽,就可以保证在当前 CPU 中的所有操作都不会被中断,从而保证了原子性。在单核 CPU 上, 通过操作 EFLAGS 寄存器相当于保存 EFLAGS 表示中断
一、Linux 内核中断控制
如果是在单核 CPU 上,情况又当如何在中断程序中也要获取自旋锁,那么可能造成和应用程序自旋锁相互争用,从而造成死锁。然而,能否将本地的中断禁止,以完成在单核 CPU 上的原子性操作,当我们完成操作后再打开中断。
同时,如果进程在内核中工作,当有高优先级的任务需要被紧急处理时,那么能否在内核态中对其进行抢占呢?
本节将详细描述 Linux 内核中断控制与内核抢占原理。下面看看实现原理。
1、中断原理
从前述理论得知,CPU 对于任务切换是通过时钟中断来控制的,只要我们将中断屏蔽,就可以保证在当前 CPU 中的所有操作都不会被中断,从而保证了原子性。
可能有读者会想,既然有了关中断,为什么还需要信号量、互斥量、自旋锁?
这很简单,在 SMP 即对称多处理器架构中,多个 CPU 共享内存。由于不可以将全部 CPU 的中断都关闭,因此为了支撑 SMP 架构,除了本地中断被关闭之外,还可以通过自旋锁来保证任务操作原子性。
上前述内容在讲解理论时,已经介绍了关中断和开中断的汇编指令 CLI、STI。现在我们来看看所有与中断相关的操作。
2、Linux 内核源码解析
首先将 EFLAGS 寄存器入栈,然后弹出放入所传入的 x 变量中,相当于保存 EFLAGS;将传入的 x 变量入栈,然后弹出放入 EFLAGS 寄存器中。
相当于恢复 EFLAGS 到中,禁止本地 CPU 中断请求,打开本地 CPU 中断请求
判断是否已经禁止了中断请求。可以看到,这里取 EFLAGS 的第九位,看看是否为 0,保存本地 EFLAGS 且禁止中断。这里与 local save flags 不同之处在于,最后的 cli,相当于保存了 EFLAGS,且禁止本地 CPU 中断,local_save flags 只保存了 EFL AGS 并没有禁止中断
二、EFLAGS 寄存器
与中断相关的操作也仅仅只是上面这些了,是不是是很简单,但是我们还是忽略了一个东西,那就是 EFLAGS 寄存器,这到底是是个什么东西呢?
EFLAGS 寄存器包含了一组状态标志、控制标志、系统标志的寄存器。处理器在初始化时将其初始
化为 00000002H。1、3、5、15 和 22~31 保留未使用。 当然,这里不能依赖这些保留未使用的状态位。
1、EFLAGS 寄存器图解
EFLAGS 寄存器的详细描述如下图所示
S 代表状态标志;C 代表控制标志;X 代表系统标志;
其中,状态标志有 6 个;控制标志有 1 个;系统标志有 10 个。
一些标志位可以通过特殊的汇编指令来修改,但是这些可被修改的汇编指令都不能直接对这个寄存器进行操作,只能间接设置。例如,可以通过 LAHF、SAHF、PUSHFD、POPF、POPFD 这些指令来从 EAX 寄存器或者栈中加载或者存标志位
上面的带 L 就是 LOAD,带 S 的就是 STORE。
当通过寄存器或者栈保存好之前的状态位后,就可以通过位操作指令 BT(位测试)、BTS(位测试并设置值)、BTR(位测试并复位值)、BTC(位测试并取反)来检测或者设置状态值。
当挂起一个任务时,CPU 将会自动保存 EFLAGS 寄存器的内容到任务状态段即 TSS 中,下一次在调度任务时再恢复。当然不止有任务切换时会这样做,当我们任务在进行中断或者异常处理时也会保存 EFLAGS 寄存器的值。
2、EFLAGS 寄存器状态标志位
状态标志位,即 0、2、4、6、7、11 标明了 ADD、SUB、MUL、DIV 等算术逻辑运算指令的操作结果。
3、EFLAGS 寄存器控制标志位
控制标志位,只有一个 DF 标志。
这个方向标志(位于 EFLAGS 寄存器的第 10 位)控制串指令(MOVS、 CMPS、SCAS、LODS 和 STOS)。设置 DF 标志使得串指令自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。STD 和 CLD 指令分别用于设置和清除 DF 标志。
4、EFLAGS 寄存器系统标志位
EFLAGS 寄存器中的系统标志位部分标志位用于控制操作系统或执行操作,它们不允许被应用程序所修改。
总结
CPU 对于任务切换是通过时钟中断来控制的,只要我们将中断屏蔽,就可以保证在当前 CPU 中的所有操作都不会被中断,从而保证了原子性。在单核 CPU 上, 通过操作 EFLAGS 寄存器相当于保存 EFLAGS 表示中断。
版权声明: 本文为 InfoQ 作者【小明Java问道之路】的原创文章。
原文链接:【http://xie.infoq.cn/article/16f36ff23ac204fbb935a899d】。文章转载请联系作者。
评论