文章目录
- 1、中断屏蔽思想
- 2、Linux内核中断屏蔽的实现
- 2.1 Linux内核提供的API接口
- 2.2 API接口实现分析
- 2.2.1 local_irq_enable
- 2.2.2 arch_local_irq_disable
- 2.2.3 arch_local_irq_save
- 2.2.4 arch_local_irq_restore
- 3、总结
1、中断屏蔽思想
中断屏蔽,正如其名,屏蔽掉CPU
的中断响应功能,解决并发引起的竞态问题。
在进入临界区前屏蔽中断,这么做有什么好处,以及有什么弊端?
好处在于:
- 保证在执行临界区代码时,不被中断所打断
- 同时,系统的进程调度与中断息息相关,同时也限制了系统进程的并发,解决了系统进程并发带来的竞态问题。
弊端在于:
Linux
内核中,除了系统进程调度依赖中断,还有一些异步I/O
等众多操作都依赖中断,因此长时间屏蔽中断是很危险的,会对系统造成严重影响,因此也要求临界区代码要简短。- 关闭中断能够解决进程调度、中断引发的竞态,但是这些都是单
CPU
内部的,对于SMP
对称多处理器,仍然不可避免的会收到其他CPU
的中断。因此,并不能解决SMP
多CPU
引发的竞态
因此,单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法
2、Linux内核中断屏蔽的实现
2.1 Linux内核提供的API接口
关于中断屏蔽,
Linux
内核所提供的接口如下:
local_irq_enable() // 使能本CPU的中断
local_irq_disable() // 禁止本CPU的中断
local_irq_save(flags) // 禁止本CPU的中断,并保存CPU中断位的信息
local_irq_restore(flags) // 使能本CPU的中断,并恢复CPU中断位的信息
local_bh_disable(void) // 禁止本CPU底半部中断
local_bh_enable(void) // 使能本CPU底半部中断
2.2 API接口实现分析
因为中断屏蔽与底层芯片架构有关,不同架构处理方式不同,我们以
ARM
为例
2.2.1 local_irq_enable
#define local_irq_enable() do { raw_local_irq_enable(); } while (0)
#define raw_local_irq_enable() arch_local_irq_enable()
#define arch_local_irq_enable arch_local_irq_enable
static inline void arch_local_irq_enable(void)
{
asm volatile(
" cpsie i @ arch_local_irq_enable"
:
:
: "memory", "cc");
}
函数介绍:local_irq_enable
函数用于将CPSR
寄存器中的中断使能位设为1,从而使得CPU
能够响应中断。
相关实现:
asm
:声明一个内联汇编表达式
cpsie i
:汇编指令,设置CPSR
寄存器的I
位,来允许本CPU
响应中断。
memory
:向汇编说明,此处内存发生了更改,类似于内存屏障的作用
cc
:表示可能会修改条件码的标志
汇编代码语法:https://www.jianshu.com/p/57fef17149ae
2.2.2 arch_local_irq_disable
#define arch_local_irq_disable arch_local_irq_disable
static inline void arch_local_irq_disable(void)
{
asm volatile(
" cpsid i @ arch_local_irq_disable"
:
:
: "memory", "cc");
}
函数介绍:arch_local_irq_disable
函数用于将CPSR
寄存器中的中断使能位设为0,从而禁止CPU
响应中断。
相关实现:同上
cpsid
:是汇编指令,用于清除CPSR
寄存器的中断标志,以禁止中断!
2.2.3 arch_local_irq_save
#define arch_local_irq_save arch_local_irq_save
static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags;
asm volatile(
" mrs %0, " IRQMASK_REG_NAME_R " @ arch_local_irq_save\n"
" cpsid i"
: "=r" (flags) : : "memory", "cc");
return flags;
}
函数介绍:arch_local_irq_save
函数,用于保存当前中断状态并禁用中断。
相关实现:
mrs %0 IRQMASK_REG_NAME_R
:mrs
指令将由IRQMASK_REG_NAME_R
宏指定的IRQMASK
寄存器的值移动到flags
变量中。
MRS命令详解
汇编命令汇总
2.2.4 arch_local_irq_restore
/*
* restore saved IRQ & FIQ state
*/
#define arch_local_irq_restore arch_local_irq_restore
static inline void arch_local_irq_restore(unsigned long flags)
{
asm volatile(
" msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
:
: "r" (flags)
: "memory", "cc");
}
函数介绍:arch_local_irq_restore
函数,用于恢复当前中断状态并打开中断。
相关实现:同上
关于
local_bh_disable
和local_bh_enable
两个接口,涉及到中断底半部机制,内容较为复杂,放在后面单独拆解!
3、总结
该篇文章,主要了解以下几点:
- 中断屏蔽的思想
- 中断屏蔽的好处与不足
Linux
内核提供的中断屏蔽接口- 中断屏蔽的基本汇编实现
点赞+关注,永远不迷路