互斥与同步——local irq enable与local irq disable

本文深入解析了Linux系统中local_irq_enable和local_irq_disable宏的作用及其实现原理,特别是在ARM架构下的具体指令。介绍了如何在单处理器不可抢占系统中使用这些宏进行共享资源保护,以及它们的变体local_irq_save和local_irq_restore的使用方法。
               

互斥与同步——local_irq_enable与local_irq_disable

内核版本:2.6.30

平台:arm

 在单处理器不可抢占系统中,使用local_irq_enable和local_irq_disable是消除异步并发源的有效方式。在驱动程序中要避免使用这两个宏(系统不能长时间不响应中断),后面将要介绍的自旋锁等互斥机制中会经常用到这两个宏。local_irq_enable宏用于打开本地处理器的中断,local_irq_disable宏则用来关闭本处理器的中断。这两个宏的定义如下:

Linux/include/linux/irqflags.h  59 #define local_irq_enable() \ 60         do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0) 61 #define local_irq_disable() \ 62         do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) 
其中 trace_hardirqs_on()和trace_hardirqs_off()用于调试,这里重点讲解raw_local_irq_enable()和raw_local_irq_disable(),这两个宏的具体实现都依赖于处理器架构,不同的处理器有不同的指令来关闭或启用处理器响应外部中断的能力。下面是ARM平台的实现:

Linux/arch/arm/include/asm/irqflags.h   8 /*  9  * CPU interrupt mask handling. 10  */ 11 #if __LINUX_ARM_ARCH__ >= 6 //ARMv6以后的指令集,通过CPSIE指令完成 21 #define raw_local_irq_enable()  __asm__("cpsie i        @ __sti" : : : "memory", "cc") 22 #define raw_local_irq_disable() __asm__("cpsid i        @ __cli" : : : "memory", "cc") 23 #define local_fiq_enable()  __asm__("cpsie f    @ __stf" : : : "memory", "cc") 24 #define local_fiq_disable() __asm__("cpsid f    @ __clf" : : : "memory", "cc") 25  26 #else//ARMv6以前的指令集,S3C2440的指令集是ARMv4T,通过mrs和msr指令完成 27  28 /* 29  * Save the current interrupt enable state & disable IRQs 30  */ 43          44 /* 45  * Enable IRQs 46  */ 47 #define raw_local_irq_enable()                                  \ 48         ({                                                      \ 49                 unsigned long temp;                             \ 50         __asm__ __volatile__(                                   \ 51         "mrs    %0, cpsr                @ local_irq_enable\n"   \ 52 "       bic     %0, %0, #128\n"                                 \ 53 "       msr     cpsr_c, %0"                                     \  //cpsr_c代表低8位 54         : "=r" (temp)                                           \ 55         :                                                       \ 56         : "memory", "cc");                                      \ 57         }) 58  59 /* 60  * Disable IRQs 61  */ 62 #define raw_local_irq_disable()                                 \ 63         ({                                                      \ 64                 unsigned long temp;                             \ 65         __asm__ __volatile__(                                   \ 66         "mrs    %0, cpsr                @ local_irq_disable\n"  \ 67 "       orr     %0, %0, #128\n"                                 \ 68 "       msr     cpsr_c, %0"                                     \ 69         : "=r" (temp)                                           \ 70         :                                                       \ 71         : "memory", "cc");                                      \ 72         })103 104 #endif

  在单处理器不可抢占系统中,如果某段代码要访问某共享资源,那么在进入临界区前使用local_irq_disable关闭中断,这样在临界区中可以保证不会出现异步并发源,访问完成共享数据在出临界区时,再调用local_irq_enable启用中断。

 local_irq_disable和local_irq_enable还有一种变体:local_irq_save和local_irq_restore,其定义如下:

Linux/include/linux/irqflags.h 63 #define local_irq_save(flags)                           \ 64         do {                                            \ 65                 typecheck(unsigned long, flags);        \ 66                 raw_local_irq_save(flags);              \ 67                 trace_hardirqs_off();                   \ 68         } while (0) 69  70  71 #define local_irq_restore(flags)                        \ 72         do {                                            \ 73                 typecheck(unsigned long, flags);        \ 74                 if (raw_irqs_disabled_flags(flags)) {   \ 75                         raw_local_irq_restore(flags);   \ 76                         trace_hardirqs_off();           \ 77                 } else {                                \ 78                         trace_hardirqs_on();            \ 79                         raw_local_irq_restore(flags);   \ 80                 }                                       \ 81         } while (0)
 这两个宏相对于 local_irq_disable和 local_irq_enable最大的区别在于,local_irq_save会在关闭中断前,将处理器当前的标志位保持在一个unsigned long flags中,在调用local_irq_restore时,在将保存的flags恢复到处理器的FLAGS寄存器中。这样做是为了防止在一个关闭中断的环境中因为调用local_irq_disable和local_irq_enable破坏之前的中断响应状态。

 我们接下来再看一下raw_local_irq_save和raw_local_irq_save和raw_local_irq_restore的具体实现:

Linux/arch/arm/include/asm/irqflags.h 11 #if __LINUX_ARM_ARCH__ >= 6 12  13 #define raw_local_irq_save(x)                                   \ 14         ({                                                      \ 15         __asm__ __volatile__(                                   \ 16         "mrs    %0, cpsr                @ local_irq_save\n"     \ 17         "cpsid  i"                                              \ 18         : "=r" (x) : : "memory", "cc");                         \ 19         })  26 #else 27  28 /* 29  * Save the current interrupt enable state & disable IRQs 30  */ 31 #define raw_local_irq_save(x)                                   \ 32         ({                                                      \ 33                 unsigned long temp;                             \ 34                 (void) (&temp == &x);                           \ 35         __asm__ __volatile__(                                   \ 36         "mrs    %0, cpsr                @ local_irq_save\n"     \ 37 "       orr     %1, %0, #128\n"                                 \ 38 "       msr     cpsr_c, %1"                                     \ 39         : "=r" (x), "=r" (temp)                                 \ 40         :                                                       \ 41         : "memory", "cc");                                      \ 42         })104 #endif116 /*117  * restore saved IRQ & FIQ state118  */119 #define raw_local_irq_restore(x)                                \120         __asm__ __volatile__(                                   \121         "msr    cpsr_c, %0              @ local_irq_restore\n"  \122         :                                                       \123         : "r" (x)                                               \124         : "memory", "cc")125 
 在单处理器不可抢占系统中,使用 local_irq_disable和 local_irq_enable及其变体对共享数据保护是简单而有效的方法。但在使用时要注意,因为local_irq_disable和local_irq_enable是通过关闭中断的方式进行互斥保护,所以必须确保处于两者之间的代码执行时间不能太长,否则将影响系统的性能。

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值