laocal_irq_enable (diaable) /_save(restore)

本文介紹了在ARM平台及2.6.30內核版本的Linux系統中,如何使用local_irq_enable和local_irq_disable宏進行中斷的開啟與關閉。這些宏在單處理器不可搶占系統中被用來確保代碼執行期間不會被中斷,從而實現對共享資源的安全訪問。

http://fanli7.net/a/bianchengyuyan/C__/20120725/192687.html

內核版本: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 #endif

116 /*
117  * restore saved IRQ & FIQ state
118  */
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://www.cnblogs.com/tureno/articles/6069331.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值