内核的同步机制(原子锁)

转自https://blog.csdn.net/fenglifeng1987/article/details/8172975

摘自《linux设备驱动开发详解》第七章

1.设置原子变量的值
           void atomic_set(atomic_t *v, int i); //设置原子变量的值为i
           atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
2.获取原子变量的值
            atomic_read(atomic_t *v); //返回原子变量的值
3.原子变量加/减
           void atomic_add(int i, atomic_t *v); //原子变量增加i
           void atomic_sub(int i, atomic_t *v); //原子变量减少i
4.原子变量自增/自减
          void atomic_inc(atomic_t *v); //原子变量增加1
          void atomic_dec(atomic_t *v); //原子变量减少1

5.操作并测试
            int atomic_inc_and_test(atomic_t *v);
            int atomic_dec_and_test(atomic_t *v);
            int atomic_sub_and_test(int i, atomic_t *v);
上述操作对原子变量执行自增、自减和减操作后(注意没有加)测试其是否为0,
为0 则返回true,否则返回false。
6.操作并返回
           int atomic_add_return(int i, atomic_t *v);
           int atomic_sub_return(int i, atomic_t *v);
           int atomic_inc_return(atomic_t *v);
           int atomic_dec_return(atomic_t *v);
上述操作对原子变量进行加/减和自增/自减操作,并返回新的值。

       atomic。在atomic.h中有着它的定义以及操作函数。

 
  1. typedef struct { volatile int counter; } atomic_t;

  2.  
  3. #define ATOMIC_INIT(i) { (i) }

  4.  
  5. /*

  6. * atomic_read - read atomic variable

  7. * @v: pointer of type atomic_t

  8. *

  9. * Atomically reads the value of @v.

  10. */

  11. #define atomic_read(v) ((v)->counter)

  12.  
  13. /*

  14. * atomic_set - set atomic variable

  15. * @v: pointer of type atomic_t

  16. * @i: required value

  17. *

  18. * Atomically sets the value of @v to @i.

  19. */

  20. #define atomic_set(v,i) ((v)->counter = (i))

  21.  
  22. /*

  23. * atomic_add - add integer to atomic variable

  24. * @i: integer value to add

  25. * @v: pointer of type atomic_t

  26. *

  27. * Atomically adds @i to @v.

  28. */

  29. static __inline__ void atomic_add(int i, atomic_t * v)

  30. {

  31. if (cpu_has_llsc && R10000_LLSC_WAR) {

  32. unsigned long temp;

  33.  
  34. __asm__ __volatile__(

  35. " .set mips3 \n"

  36. "1: ll %0, %1 # atomic_add \n"

  37. " addu %0, %2 \n"

  38. " sc %0, %1 \n"

  39. " beqzl %0, 1b \n"

  40. " .set mips0 \n"

  41. : "=&r" (temp), "=m" (v->counter)

  42. : "Ir" (i), "m" (v->counter));

  43. } else if (cpu_has_llsc) {

  44. unsigned long temp;

  45.  
  46. __asm__ __volatile__(

  47. " .set mips3 \n"

  48. "1: ll %0, %1 # atomic_add \n"

  49. " addu %0, %2 \n"

  50. " sc %0, %1 \n"

  51. " beqz %0, 2f \n"

  52. " .subsection 2 \n"

  53. "2: b 1b \n"

  54. " .previous \n"

  55. " .set mips0 \n"

  56. : "=&r" (temp), "=m" (v->counter)

  57. : "Ir" (i), "m" (v->counter));

  58. } else {

  59. unsigned long flags;

  60.  
  61. raw_local_irq_save(flags);

  62. v->counter += i;

  63. raw_local_irq_restore(flags);

  64. }

  65. }

  66.  
  67. /*

  68. * atomic_sub - subtract the atomic variable

  69. * @i: integer value to subtract

  70. * @v: pointer of type atomic_t

  71. *

  72. * Atomically subtracts @i from @v.

  73. */

  74. static __inline__ void atomic_sub(int i, atomic_t * v)

  75. {

  76. if (cpu_has_llsc && R10000_LLSC_WAR) {

  77. unsigned long temp;

  78.  
  79. __asm__ __volatile__(

  80. " .set mips3 \n"

  81. "1: ll %0, %1 # atomic_sub \n"

  82. " subu %0, %2 \n"

  83. " sc %0, %1 \n"

  84. " beqzl %0, 1b \n"

  85. " .set mips0 \n"

  86. : "=&r" (temp), "=m" (v->counter)

  87. : "Ir" (i), "m" (v->counter));

  88. } else if (cpu_has_llsc) {

  89. unsigned long temp;

  90.  
  91. __asm__ __volatile__(

  92. " .set mips3 \n"

  93. "1: ll %0, %1 # atomic_sub \n"

  94. " subu %0, %2 \n"

  95. " sc %0, %1 \n"

  96. " beqz %0, 2f \n"

  97. " .subsection 2 \n"

  98. "2: b 1b \n"

  99. " .previous \n"

  100. " .set mips0 \n"

  101. : "=&r" (temp), "=m" (v->counter)

  102. : "Ir" (i), "m" (v->counter));

  103. } else {

  104. unsigned long flags;

  105.  
  106. raw_local_irq_save(flags);

  107. v->counter -= i;

  108. raw_local_irq_restore(flags);

  109. }

  110. }

 
  1. /*

  2.  * atomic_sub_and_test - subtract value from variable and test result

  3.  * @i: integer value to subtract

  4.  * @v: pointer of type atomic_t

  5.  *

  6.  * Atomically subtracts @i from @v and returns

  7.  * true if the result is zero, or false for all

  8.  * other cases.

  9.  */

  10. #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)

  11.  
  12.  
  13. /*

  14.  * atomic_inc_and_test - increment and test

  15.  * @v: pointer of type atomic_t

  16.  *

  17.  * Atomically increments @v by 1

  18.  * and returns true if the result is zero, or false for all

  19.  * other cases.

  20.  */

  21. #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)

  22.  
  23.  
  24. /*

  25.  * atomic_dec_and_test - decrement by 1 and test

  26.  * @v: pointer of type atomic_t

  27.  *

  28.  * Atomically decrements @v by 1 and

  29.  * returns true if the result is 0, or false for all other

  30.  * cases.

  31.  */

  32. #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)

  33.  

其实就是设置一个整形变量,对这个整形变量进行加减操作。可应用于对引用资源的计数。

        在对这个整形变量进行加减的过程中,是在原子状态下进行的,汇编语言先不管,那几段少的可怜的c代码中,v->count进行加减的时候都是要关中断的。确保当前process占用内核。

       原子锁也可以用于同步。比如下面的程序,至允许在一个进程中打开资源。程序也是摘自《linux设备驱动详解》

  1. static atomic_t xxx_available = ATOMIC_INIT(1); /*定义原子变量*/

  2.  
  3. static int xxx_open(struct inode *inode, struct file *filp)

  4. {

  5. ...

  6. if (!atomic_dec_and_test(&xxx_available)) //如果xxx_available=0,返回1

  7. {

  8. atomic_inc(&xxx_available);

  9. return - EBUSY; /*已经打开*/

  10. }

  11. ...

  12. return 0; /* 成功*/

  13. }

  14.  
  15. static int xxx_release(struct inode *inode, struct file *filp)

  16. {

  17. atomic_inc(&xxx_available); /* 释放设备*/

  18. return 0;

  19. }

还有位操作的的原子锁,原理跟上面的差不多,只不过这是用bit操作,这样操作更简洁明了,非0即1,就是缺少了计数这个功能。

1.设置位
          void set_bit(nr, void *addr);
         上述操作设置addr 地址的第nr 位,所谓设置位即将位写为1。
2.清除位
         void clear_bit(nr, void *addr);
       上述操作清除addr 地址的第nr 位,所谓清除位即将位写为0。
3.改变位
         void change_bit(nr, void *addr);
        上述操作对addr 地址的第nr 位进行反置。
4.测试位
         test_bit(nr, void *addr);
        上述操作返回addr 地址的第nr 位。

5.测试并操作位
         int test_and_set_bit(nr, void *addr);
         int test_and_clear_bit(nr, void *addr);
         int test_and_change_bit(nr, void *addr);
上述test_and_xxx_bit(nr, void *addr)操作等同于执行test_bit (nr, void *addr)后
再执行xxx_bit(nr, void *addr)。

猜你喜欢

转载自blog.csdn.net/wenjin359/article/details/83001823