互斥与同步——local_irq_enable与local_irq_disable

内核版本:2.6.30

平台:arm

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

[plain] view plaincopyprint?
  1. Linux/include/linux/irqflags.h
  2. 59 #define local_irq_enable() \
  3. 60         do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
  4. 61 #define local_irq_disable() \
  5. 62         do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
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平台的实现:

[plain] view plaincopyprint?
  1. Linux/arch/arm/include/asm/irqflags.h
  2. 8 /*
  3. 9  * CPU interrupt mask handling.
  4. 10  */
  5. 11 #if __LINUX_ARM_ARCH__ >= 6 //ARMv6以后的指令集,通过CPSIE指令完成
  6. 21 #define raw_local_irq_enable()  __asm__("cpsie i        @ __sti" : : : "memory", "cc")
  7. 22 #define raw_local_irq_disable() __asm__("cpsid i        @ __cli" : : : "memory", "cc")
  8. 23 #define local_fiq_enable()  __asm__("cpsie f    @ __stf" : : : "memory", "cc")
  9. 24 #define local_fiq_disable() __asm__("cpsid f    @ __clf" : : : "memory", "cc")
  10. 25
  11. 26 #else//ARMv6以前的指令集,S3C2440的指令集是ARMv4T,通过mrs和msr指令完成
  12. 27
  13. 28 /*
  14. 29  * Save the current interrupt enable state & disable IRQs
  15. 30  */
  16. 43
  17. 44 /*
  18. 45  * Enable IRQs
  19. 46  */
  20. 47 #define raw_local_irq_enable()                                  \
  21. 48         ({                                                      \
  22. 49                 unsigned long temp;                             \
  23. 50         __asm__ __volatile__(                                   \
  24. 51         "mrs    %0, cpsr                @ local_irq_enable\n"   \
  25. 52 "       bic     %0, %0, #128\n"                                 \
  26. 53 "       msr     cpsr_c, %0"                                     \  //cpsr_c代表低8位
  27. 54         : "=r" (temp)                                           \
  28. 55         :                                                       \
  29. 56         : "memory", "cc");                                      \
  30. 57         })
  31. 58
  32. 59 /*
  33. 60  * Disable IRQs
  34. 61  */
  35. 62 #define raw_local_irq_disable()                                 \
  36. 63         ({                                                      \
  37. 64                 unsigned long temp;                             \
  38. 65         __asm__ __volatile__(                                   \
  39. 66         "mrs    %0, cpsr                @ local_irq_disable\n"  \
  40. 67 "       orr     %0, %0, #128\n"                                 \
  41. 68 "       msr     cpsr_c, %0"                                     \
  42. 69         : "=r" (temp)                                           \
  43. 70         :                                                       \
  44. 71         : "memory", "cc");                                      \
  45. 72         })
  46. 103
  47. 104 #endif
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,其定义如下:

[plain] view plaincopyprint?
  1. Linux/include/linux/irqflags.h
  2. 63 #define local_irq_save(flags)                           \
  3. 64         do {                                            \
  4. 65                 typecheck(unsigned long, flags);        \
  5. 66                 raw_local_irq_save(flags);              \
  6. 67                 trace_hardirqs_off();                   \
  7. 68         } while (0)
  8. 69
  9. 70
  10. 71 #define local_irq_restore(flags)                        \
  11. 72         do {                                            \
  12. 73                 typecheck(unsigned long, flags);        \
  13. 74                 if (raw_irqs_disabled_flags(flags)) {   \
  14. 75                         raw_local_irq_restore(flags);   \
  15. 76                         trace_hardirqs_off();           \
  16. 77                 } else {                                \
  17. 78                         trace_hardirqs_on();            \
  18. 79                         raw_local_irq_restore(flags);   \
  19. 80                 }                                       \
  20. 81         } while (0)
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的具体实现:

[plain] view plaincopyprint?
  1. Linux/arch/arm/include/asm/irqflags.h
  2. 11 #if __LINUX_ARM_ARCH__ >= 6
  3. 12
  4. 13 #define raw_local_irq_save(x)                                   \
  5. 14         ({                                                      \
  6. 15         __asm__ __volatile__(                                   \
  7. 16         "mrs    %0, cpsr                @ local_irq_save\n"     \
  8. 17         "cpsid  i"                                              \
  9. 18         : "=r" (x) : : "memory", "cc");                         \
  10. 19         })
  11. 26 #else
  12. 27
  13. 28 /*
  14. 29  * Save the current interrupt enable state & disable IRQs
  15. 30  */
  16. 31 #define raw_local_irq_save(x)                                   \
  17. 32         ({                                                      \
  18. 33                 unsigned long temp;                             \
  19. 34                 (void) (&temp == &x);                           \
  20. 35         __asm__ __volatile__(                                   \
  21. 36         "mrs    %0, cpsr                @ local_irq_save\n"     \
  22. 37 "       orr     %1, %0, #128\n"                                 \
  23. 38 "       msr     cpsr_c, %1"                                     \
  24. 39         : "=r" (x), "=r" (temp)                                 \
  25. 40         :                                                       \
  26. 41         : "memory", "cc");                                      \
  27. 42         })
  28. 104 #endif
  29. 116 /*
  30. 117  * restore saved IRQ & FIQ state
  31. 118  */
  32. 119 #define raw_local_irq_restore(x)                                \
  33. 120         __asm__ __volatile__(                                   \
  34. 121         "msr    cpsr_c, %0              @ local_irq_restore\n"  \
  35. 122         :                                                       \
  36. 123         : "r" (x)                                               \
  37. 124         : "memory", "cc")
  38. 125
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是通过关闭中断的方式进行互斥保护,所以必须确保处于两者之间的代码执行时间不能太长,否则将影响系统的性能。

互斥与同步——local_irq_enable与local_irq_disable相关推荐

  1. 如何避免操作系统中多线程资源竞争的互斥与同步?

    作者 | 小林coding 来源 | 小林coding(ID:CodingLin) 前言 先来看看虚构的小故事 已经晚上 11 点了,程序员小明的双手还在键盘上飞舞着,眼神依然注视着的电脑屏幕. 没办 ...

  2. python多线程编程(2): 使用互斥锁同步线程

    上一节的例子中,每个线程互相独立,相互之间没有任何关系.现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1.很容易写出这样的代码: # ...

  3. 操作系统习题3—进程的互斥与同步

    操作系统习题3-进程的互斥与同步 1.例举两个现实生活中需要同步与互斥的例子. 我们去吃自助餐时,店里的厨师会在后台厨房制作食物,然后将食物运送到公共饮食区域,让顾客自行挑选.如果公共饮食区域的食物都 ...

  4. [OS复习]进程互斥与同步2

    互斥与同步的解决策略 当前,利用软件方法.硬件方法.信号量方法.管程方法.消息传递方法都可以有效地解决进程间的互斥与同步,其中信号量的方法更具有优势(目前已经通用). 1. 软件方法: 软件方法是指由 ...

  5. [OS复习]进程互斥与同步1

    进程互斥与同步 1.引言:多道程序设计存在的问题? 采用多道程序设计技术的操作系统,允许多个进程同时驻留内存并发执行.思考: A.如何协调多个进程对系统资源,如内存空间.外部设备等的竞争和共享? B. ...

  6. 通过一道题目来理解互斥和同步

    文章目录 前言 题目:判断下列问题的算法是否正确?若不正确,如何改正? 解答与剖析 第一小问:同步问题 解答 剖析 第二小问:互斥问题 解答 剖析 前言 在进程的学习中,互斥和同步是最重点的内容,但由 ...

  7. 操作系统(二十二)用信号量机制实现进程互斥、同步、前驱关系

    2.3.5 用信号量机制实现进程互斥.同步.前驱关系 目录 2.3.5 用信号量机制实现进程互斥.同步.前驱关系 2.3.5.1 用信号量机制实现进程互斥 2.3.5.2 用信号量机制实现进程同步 2 ...

  8. Android ContentProvider支持跨进程数据共享与互斥、同步 杂谈

    在开发中,假如,A.B进程有部分信息需要同步,这个时候怎么处理呢?设想这么一个场景,有个业务复杂的Activity非常占用内存,并引发OOM,所以,想要把这个Activity放到单独进程,以保证OOM ...

  9. python 线程锁_python多线程编程(3): 使用互斥锁同步线程

    问题的提出 上一节的例子中,每个线程互相独立,相互之间没有任何关系.现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1.很容易写出这样的 ...

最新文章

  1. 数据结构线段树介绍与笔试算法题-LeetCode 307. Range Sum Query - Mutable--Java解法
  2. 如何寻找outlook邮件附件直接修改保存后的文档
  3. 第二阶段冲刺第十天,6月9日。
  4. #!/usr/bin/env python与#!/usr/bin/python的区别
  5. Boost enable_if库的测试程序
  6. MySQL8.0 - 新特性 - 安全及权限相关改进
  7. LCS-最大公共子序列(DP问题)
  8. input子系统分析二
  9. Web开发必学的8个网页优化技巧!
  10. oracle创建触发器
  11. DB2数据库常用基本操作命令
  12. Using OpenCV Java with Eclipse
  13. debian 修改apache2 https 端口为11443
  14. 抖音小程序的私域运营
  15. 电子基础知识:测判三极管的口诀
  16. 【采样算法】拉丁超立方采样
  17. 2个DIV制作十字架
  18. 滤波反投影重建算法(FBP)实现及应用(matlab)
  19. 【正则表达式】字符串模式匹配,提高开发效率
  20. 计算机芯片材料晶体硅,硅晶片

热门文章

  1. java锁包读写锁_java8读写锁如何使用
  2. Python读写与追加excel文件
  3. python123测验4程序题_Python面试题245道(从基础到高级)123~141——网络编程,Web—Flask...
  4. easymodbus_easymodbus4j基于netty的modbus协议快速开发工具
  5. 误差函数拟合优缺点_欠拟合、过拟合及如何防止过拟合
  6. 在windows环境中关于 pycharm配置 anaconda 虚拟环境
  7. javeWeb springMvc获取到的参数附带特殊符号,接收后被转义
  8. fetch移动端浏览器兼容问题
  9. HDOJ 1021-1025
  10. [Alamofire] 错误总结