曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 13085|回复: 0
打印 上一主题 下一主题

local_irq_disable() | local_irq_enable() | local_irq_save() | local_irq_resto

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-2-20 22:11:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
平台:x86
内核:2.6.23


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定义为:

[Plain Text] 纯文本查看 复制代码
static inline void raw_local_irq_disable(void){    native_irq_disable();    }


从 native_irq_disable() 的名字可以看到是”禁止本地中断“ 。禁止本地中断并不保护运行在另一个CPU上的中断处理程序对该数据结构的并发访问。native_irq_disable() 同样定义在 include/asm-i386/Irqflag.h 中:

[Plain Text] 纯文本查看 复制代码
static inline void native_irq_disable(void){    asm volatile("cli": : :"memory");}


指令 cli 会清除 eflags 控制寄存器中的IF标志,这样就禁止了中断。


同样可以看到 local_irq_enable() 的最终定义为:

[Plain Text] 纯文本查看 复制代码
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() 有:

[Plain Text] 纯文本查看 复制代码
static inline unsigned long native_save_fl(void){    unsigned long f;    asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);    return f;}


上面,先将 eflags 压入栈中,然后再弹出到 f 变量中将其保存起来。


对应于 local_irq_restore() 有:

[Plain Text] 纯文本查看 复制代码
static inline void native_restore_fl(unsigned long f){    asm volatile("pushl %0 ; popfl": /* no output */                 :"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()。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-6 08:26 , Processed in 0.078829 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表