local_irq_disable() , local_irq_enable() , local_irq_save() 和 local_irq_restore()

【转自】

local_irq_disable() , local_irq_enable() , local_irq_save() 和 local_irq_restore() 为中断处理函数,主要是在要进入临界区时禁止中断和在出临界区时使能中断。

local_irq_disable() 和 local_irq_enable() 配对使用;
local_irq_save() 和  local_irq_restore()  配对使用。

local_irq_disable() 和 local_irq_save() 都可以禁止中断,但不同的是后者可以保存中断状态。
local_irq_restore() 在使能中断的同时还恢复了由 local_irq_save() 所保存的中断状态。


这 4 个宏定义在 include/linux/Irqflag.h 中:

#define local_irq_enable() \

    do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
#define local_irq_disable() \
    do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
#define local_irq_save(flags) \
    do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0)
#define local_irq_restore(flags)                \
    do {                            \
        if (raw_irqs_disabled_flags(flags)) {        \
            raw_local_irq_restore(flags);        \
            trace_hardirqs_off();            \
        } else {                    \
            trace_hardirqs_on();            \
            raw_local_irq_restore(flags);        \
        }                        \
    } while (0)

其中,raw_local_irq_disable() 在 include/asm-i386/Irqflag.h定义为:

static inline void raw_local_irq_disable(void){    native_irq_disable();    }
从 native_irq_disable() 的名字可以看到是”禁止本地中断“ 。禁止本地中断并不保护运行在另一个CPU上的中断处理程序对该数据结构的并发访问。native_irq_disable() 同样定义在 include/asm-i386/Irqflag.h 中:
static inline void native_irq_disable(void){    asm volatile("cli": : :"memory");}
指令 cli 会清除 eflags 控制寄存器中的IF标志,这样就禁止了中断。
同样可以看到 local_irq_enable() 的最终定义为:
static inline void native_irq_enable(void){    asm volatile("sti": : :"memory");}
指令 cli 会设置 eflags 控制寄存器中的IF标志,这样就使能了中断。

有时候,为了避免中断处理程序对 eflags 寄存器内容的破坏,在进入临界区时使用 local_irq_save() 来保存 eflags 寄存器(将 elfags 保存在一个变量中)以及在出临界区时用 local_irq_restore() 来恢复 eflags 寄存器。同样在 include/asm-i386/Irqflag.h 有定义:
对应于 local_irq_save() 有:
复制代码
static inline unsigned long native_save_fl(void){    unsigned long f;    asm volatile("pushfl ; popl %0":"=g" (f): );    return f;}
上面,先将 eflags 压入栈中,然后再弹出到 f 变量中将其保存起来。


对应于 local_irq_restore() 有:

static inline void native_restore_fl(unsigned long f){    asm volatile("pushl %0 ; popfl":           :"g" (f)                 :"memory", "cc");}

上面,将变量 f 压入栈,然后弹到 eflags 中。另外,cc 是因为汇编指令会修改 eflags 寄存器时而采用。
对于单 CPU,非抢占的情况,假如有:
local_irq_disable()
local_irq_enable()


转自这里,如果当执行到 local_irq_disable() 时,中断已经被禁止。那么在退出临界区时,再执行 local_irq_enable() 时会使所有的中断都打开,这样是可能带来副作用的,修正这种情况的办法是使用 local_irq_save() 和 local_irq_restore()。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值