Chinaunix首页 | 论坛 | 博客
  • 博客访问: 169204
  • 博文数量: 123
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 11
  • 用 户 组: 普通用户
  • 注册时间: 2015-06-20 19:04
文章分类

全部博文(123)

文章存档

2015年(123)

我的朋友

分类: LINUX

2015-06-21 11:48:00

    一 原子操作
    所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或者事件打断,也就所说,它是最小的执行单元,不可能有更小的执行单元,因此这里的原子实际是使用了物理学里面道物质微粒的概念。
    原子操作需要硬件的支持,因此是架构相关的,其api和原子类型道定义都定义在内核源码树的include\asm-x86_64\atomic.h,下面仅仅正对x86-64处理器类型进行举例说明。其由汇编实现,因为C语言并不能实现这样的操作。    
    我们通过分析其具体实现来了解其功能。在进行源码分析之前,可以先了解内联汇编的使用,这样有助于理解源代码。 
    下面对具体代码进行分析:
 

点击(此处)折叠或打开

  1. #ifdef CONFIG_SMP
  2. #define LOCK "lock ; "
  3. #else
  4. #define LOCK ""
  5. #endif
  6. CONFIG_SMP 配置选项控制内核是否支持SMP,针对指定机器进行内核裁剪只用。

  7. /*
  8.  * Make sure gcc doesn't try to be clever and move things around
  9.  * on us. We need to use _exactly_ the address the user gave us,
  10.  * not some alias that contains the same information.
  11.  */
  12. typedef struct { volatile int counter; } atomic_t;
  13. 定义atomic_t结构,实际上包含一个整形的变量,使用volatile 修饰,告诉gcc不要对该类型的数据进行优化处理,对它的访问都是对内存访问,而不是对寄存器的访问;

  14. #define ATOMIC_INIT(i)    { (i) }
  15. 初始化atomic_t

  16. /**
  17.  * atomic_read - read atomic variable
  18.  * @v: pointer of type atomic_t
  19.  *
  20.  * Atomically reads the value of @v.
  21.  */
  22. #define atomic_read(v)        ((v)->counter)
  23. 对原子类型的变量进行原子操作,它返回原子类型的变量v的值;

  24. /**
  25.  * atomic_set - set atomic variable
  26.  * @v: pointer of type atomic_t
  27.  * @i: required value
  28.  *
  29.  * Atomically sets the value of @v to @i.
  30.  */
  31. #define atomic_set(v,i)        (((v)->counter) = (i))
  32. 设置原子类型的变量v值为i;

  33. /**
  34.  * atomic_add - add integer to atomic variable
  35.  * @i: integer value to add
  36.  * @v: pointer of type atomic_t
  37.  *
  38.  * Atomically adds @i to @v.
  39.  */
  40. static __inline__ void atomic_add(int i, atomic_t *v)
  41. {
  42.     __asm__ __volatile__(
  43.         LOCK "addl %1,%0"
  44.         :"=m" (v->counter)
  45.         :"ir" (i), "m" (v->counter));
  46. }
  47. 原子类型的变量v增加值i, addl %1,%0 即实现了此原子的增加,如果了解了内联汇编,理解这段代码就很容易了;

  48. /**
  49.  * atomic_sub - subtract the atomic variable
  50.  * @i: integer value to subtract
  51.  * @v: pointer of type atomic_t
  52.  *
  53.  * Atomically subtracts @i from @v.
  54.  */
  55. static __inline__ void atomic_sub(int i, atomic_t *v)
  56. {
  57.     __asm__ __volatile__(
  58.         LOCK "subl %1,%0"
  59.         :"=m" (v->counter)
  60.         :"ir" (i), "m" (v->counter));
  61. }
  62. 原子类型的变量v减去值i;

  63. /**
  64.  * atomic_sub_and_test - subtract value from variable and test result
  65.  * @i: integer value to subtract
  66.  * @v: pointer of type atomic_t
  67.  *
  68.  * Atomically subtracts @i from @v and returns
  69.  * true if the result is zero, or false for all
  70.  * other cases.
  71.  */
  72. static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
  73. {
  74.     unsigned char c;

  75.     __asm__ __volatile__(
  76.         LOCK "subl %2,%0; sete %1"
  77.         :"=m" (v->counter), "=qm" (c)
  78.         :"ir" (i), "m" (v->counter) : "memory");
  79.     return c;
  80. }
  81. 该函数从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假;

  82. /**

  83.  * atomic_inc - increment atomic variable

  84.  * @v: pointer of type atomic_t

  85.  *

  86.  * Atomically increments @v by 1.

  87.  */

  88. static __inline__ void atomic_inc(atomic_t *v)

  89. {

  90.     __asm__ __volatile__(

  91.         LOCK "incl %0"

  92.         :"=m" (v->counter)

  93.         :"m" (v->counter));

  94. }


  95. 原子类型的变量v自增1;

  96. /**
  97.  * atomic_dec - decrement atomic variable
  98.  * @v: pointer of type atomic_t
  99.  *
  100.  * Atomically decrements @v by 1.
  101.  */
  102. static __inline__ void atomic_dec(atomic_t *v)
  103. {
  104.     __asm__ __volatile__(
  105.         LOCK "decl %0"
  106.         :"=m" (v->counter)
  107.         :"m" (v->counter));
  108. }
  109. 原子类型的变量v自减1;

  110. /**
  111.  * atomic_dec_and_test - decrement and test
  112.  * @v: pointer of type atomic_t
  113.  *
  114.  * Atomically decrements @v by 1 and
  115.  * returns true if the result is 0, or false for all other
  116.  * cases.
  117.  */
  118. static __inline__ int atomic_dec_and_test(atomic_t *v)
  119. {
  120.     unsigned char c;

  121.     __asm__ __volatile__(
  122.         LOCK "decl %0; sete %1"
  123.         :"=m" (v->counter), "=qm" (c)
  124.         :"m" (v->counter) : "memory");
  125.     return c != 0;
  126. }
  127. 对原子类型的变量v原子地减1,并判断结果是否为0,如果为0,返回真,否则返回假;

  128. /**
  129.  * atomic_inc_and_test - increment and test
  130.  * @v: pointer of type atomic_t
  131.  *
  132.  * Atomically increments @v by 1
  133.  * and returns true if the result is zero, or false for all
  134.  * other cases.
  135.  */
  136. static __inline__ int atomic_inc_and_test(atomic_t *v)
  137. {
  138.     unsigned char c;

  139.     __asm__ __volatile__(
  140.         LOCK "incl %0; sete %1"
  141.         :"=m" (v->counter), "=qm" (c)
  142.         :"m" (v->counter) : "memory");
  143.     return c != 0;
  144. }
  145. 对原子类型的变量v原子地增加1,并判断结果是否为0,如果为0,返回真,否则返回假;

  146. /**
  147.  * atomic_add_negative - add and test if negative
  148.  * @v: pointer of type atomic_t
  149.  * @i: integer value to add
  150.  *
  151.  * Atomically adds @i to @v and returns true
  152.  * if the result is negative, or false when
  153.  * result is greater than or equal to zero.
  154.  */
  155. static __inline__ int atomic_add_negative(int i, atomic_t *v)
  156. {
  157.     unsigned char c;

  158.     __asm__ __volatile__(
  159.         LOCK "addl %2,%0; sets %1"
  160.         :"=m" (v->counter), "=qm" (c)
  161.         :"ir" (i), "m" (v->counter) : "memory");
  162.     return c;
  163. }
  164. 对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假;

      原子操作通常用于实现资源的引用计数,在编写代码的时候,能使用原子操作的时候,就尽量不要使用复杂的锁机制。对于多数体系结构来说,原子与更复杂的同步方法相比较,给系统带来的开销小,对高速缓存行的影响也小。
 
    除原子整形操作外,内核还提供了一组针对这一级数据进行操作的函数,其定义在include\asm-x86_64\bitops.h中,位操作函数是对普通的内存地址进行操作的。参数为一个指针和一个位号,第0位是给定地址的最低有效位。32位机上,第31位是给定地址的最高有效位,而第32位是下一个字节的最低有效位。

点击(此处)折叠或打开

  1. #define ADDR (*(volatile long *) addr)
  2. 把addr强制转换为(volatile long ) 类型的指针,即对指针的操作范围是addr开始的4个字节(long 型),暂时记作p,那么就是
  3. #define ADDR *p,即为p指针指向位置的内容。这里可以通过内存寻址访问到寄存器ADDR,可以进行读写操作。
  4. 假设内存0xaaaaaaaa是一个寄存器,如果要访问它,可以这样:
  5. #define ADDR (*(volatile long *) 0xaaaaaaaa )
  6. 读:tmp = ADDR;
  7. 写:ADDR = 0xAABBCCDD;

  8. /**
  9.  * set_bit - Atomically set a bit in memory
  10.  * @nr: the bit to set
  11.  * @addr: the address to start counting from
  12.  *
  13.  * This function is atomic and may not be reordered. See __set_bit()
  14.  * if you do not require the atomic guarantees.
  15.  * Note that @nr may be almost arbitrarily large; this function is not
  16.  * restricted to acting on a single-word quantity.
  17.  */
  18. static __inline__ void set_bit(long nr, volatile void * addr)
  19. {
  20.     __asm__ __volatile__( LOCK_PREFIX
  21.         "btsq %1,%0"
  22.         :"=m" (ADDR)
  23.         :"dIr" (nr) : "memory");
  24. }
  25. bts( bit test and set),bts oprd1, oprd2 : 即位测试并置位,被测试位送CF并且被测试位置1;上面的内联汇编代码即将addr指向的内容第nr位置1;
  26. 此为原子操作,而且是不可重新排序的;@nr 可以很大,并非只能是单个word的数量的限制。

  27. /**
  28.  * __set_bit - Set a bit in memory
  29.  * @nr: the bit to set
  30.  * @addr: the address to start counting from
  31.  *
  32.  * Unlike set_bit(), this function is non-atomic and may be reordered.
  33.  * If it's called on the same region of memory simultaneously, the effect
  34.  * may be that only one operation succeeds.
  35.  */
  36. static __inline__ void __set_bit(int nr, volatile void * addr)
  37. {
  38.     __asm__ volatile(
  39.         "btsl %1,%0"
  40.         :"=m" (ADDR)
  41.         :"dIr" (nr) : "memory");
  42. }
  43. 非原子位操作函数,与set_bit对应,__set_bit不保证原子性,内核对每个操作都提供了原子位操作数的版本,以及非原子位操作的版本,其操作完全相同,只是后者名字前缀多两个下划线,以下仅对原子位操作进行说明。

  44. /**
  45.  * clear_bit - Clears a bit in memory
  46.  * @nr: Bit to clear
  47.  * @addr: Address to start counting from
  48.  *
  49.  * clear_bit() is atomic and may not be reordered. However, it does
  50.  * not contain a memory barrier, so if it is used for locking purposes,
  51.  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  52.  * in order to ensure changes are visible on other processors.
  53.  */
  54. static __inline__ void clear_bit(int nr, volatile void * addr)
  55. {
  56.     __asm__ __volatile__( LOCK_PREFIX
  57.         "btrl %1,%0"
  58.         :"=m" (ADDR)
  59.         :"dIr" (nr));
  60. }

  61. static __inline__ void __clear_bit(int nr, volatile void * addr)
  62. {
  63.     __asm__ __volatile__(
  64.         "btrl %1,%0"
  65.         :"=m" (ADDR)
  66.         :"dIr" (nr));
  67. }
  68. #define smp_mb__before_clear_bit()    barrier()
  69. #define smp_mb__after_clear_bit()    barrier()

  70. bts( bit test and reset), btr oprd1,oprd2 位测试并复位指令,被测试位送CF并且被测试位清0;上面的内联汇编代码原子地清除addr所指对象的第nr位。它不包含内存屏障(当多个CPU同时访问一块内存,或者CPU和设备同时访问一块内存,为了实现访问的一致性,需要内存屏障),因此只是用于锁,为了确保在其他的进程中可见,你应该先调用 smp_mb__before_clear_bit(), smp_mb__after_clear_bit()

  71. /**
  72.  * __change_bit - Toggle a bit in memory
  73.  * @nr: the bit to change
  74.  * @addr: the address to start counting from
  75.  *
  76.  * Unlike change_bit(), this function is non-atomic and may be reordered.
  77.  * If it's called on the same region of memory simultaneously, the effect
  78.  * may be that only one operation succeeds.
  79.  */
  80. static __inline__ void __change_bit(int nr, volatile void * addr)
  81. {
  82.     __asm__ __volatile__(
  83.         "btcl %1,%0"
  84.         :"=m" (ADDR)
  85.         :"dIr" (nr));
  86. }

  87. /**
  88.  * change_bit - Toggle a bit in memory
  89.  * @nr: Bit to change
  90.  * @addr: Address to start counting from
  91.  *
  92.  * change_bit() is atomic and may not be reordered.
  93.  * Note that @nr may be almost arbitrarily large; this function is not
  94.  * restricted to acting on a single-word quantity.
  95.  */
  96. static __inline__ void change_bit(int nr, volatile void * addr)
  97. {
  98.     __asm__ __volatile__( LOCK_PREFIX
  99.         "btcl %1,%0"
  100.         :"=m" (ADDR)
  101.         :"dIr" (nr));
  102. }
  103. 原子的翻转addr所指对象的第nr位;

  104. /**
  105.  * test_and_set_bit - Set a bit and return its old value
  106.  * @nr: Bit to set
  107.  * @addr: Address to count from
  108.  *
  109.  * This operation is atomic and cannot be reordered.
  110.  * It also implies a memory barrier.
  111.  */
  112. static __inline__ int test_and_set_bit(int nr, volatile void * addr)
  113. {
  114.     int oldbit;

  115.     __asm__ __volatile__( LOCK_PREFIX
  116.         "btsl %2,%1\n\tsbbl %0,%0"
  117.         :"=r" (oldbit),"=m" (ADDR)
  118.         :"dIr" (nr) : "memory");
  119.     return oldbit;
  120. }

  121. /**
  122.  * __test_and_set_bit - Set a bit and return its old value
  123.  * @nr: Bit to set
  124.  * @addr: Address to count from
  125.  *
  126.  * This operation is non-atomic and can be reordered.
  127.  * If two examples of this operation race, one can appear to succeed
  128.  * but actually fail. You must protect multiple accesses with a lock.
  129.  */
  130. static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
  131. {
  132.     int oldbit;

  133.     __asm__(
  134.         "btsl %2,%1\n\tsbbl %0,%0"
  135.         :"=r" (oldbit),"=m" (ADDR)
  136.         :"dIr" (nr));
  137.     return oldbit;
  138. }
  139. 原子的设置addr所指对象的第nr位,并返回原先的值;

  140. /**
  141.  * test_and_clear_bit - Clear a bit and return its old value
  142.  * @nr: Bit to clear
  143.  * @addr: Address to count from
  144.  *
  145.  * This operation is atomic and cannot be reordered.
  146.  * It also implies a memory barrier.
  147.  */
  148. static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
  149. {
  150.     int oldbit;

  151.     __asm__ __volatile__( LOCK_PREFIX
  152.         "btrl %2,%1\n\tsbbl %0,%0"
  153.         :"=r" (oldbit),"=m" (ADDR)
  154.         :"dIr" (nr) : "memory");
  155.     return oldbit;
  156. }

  157. /**
  158.  * __test_and_clear_bit - Clear a bit and return its old value
  159.  * @nr: Bit to clear
  160.  * @addr: Address to count from
  161.  *
  162.  * This operation is non-atomic and can be reordered.
  163.  * If two examples of this operation race, one can appear to succeed
  164.  * but actually fail. You must protect multiple accesses with a lock.
  165.  */
  166. static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
  167. {
  168.     int oldbit;

  169.     __asm__(
  170.         "btrl %2,%1\n\tsbbl %0,%0"
  171.         :"=r" (oldbit),"=m" (ADDR)
  172.         :"dIr" (nr));
  173.     return oldbit;
  174. }
  175. 原子的清空addr所指对象的第nr位,并返回原先的值;

  176. /* WARNING: non atomic and it can be */
  177. static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
  178. {
  179.     int oldbit;

  180.     __asm__ __volatile__(
  181.         "btcl %2,%1\n\tsbbl %0,%0"
  182.         :"=r" (oldbit),"=m" (ADDR)
  183.         :"dIr" (nr) : "memory");
  184.     return oldbit;
  185. }

  186. /**
  187.  * test_and_change_bit - Change a bit and return its old value
  188.  * @nr: Bit to change
  189.  * @addr: Address to count from
  190.  *
  191.  * This operation is atomic and cannot be reordered.
  192.  * It also implies a memory barrier.
  193.  */
  194. static __inline__ int test_and_change_bit(int nr, volatile void * addr)
  195. {
  196.     int oldbit;

  197.     __asm__ __volatile__( LOCK_PREFIX
  198.         "btcl %2,%1\n\tsbbl %0,%0"
  199.         :"=r" (oldbit),"=m" (ADDR)
  200.         :"dIr" (nr) : "memory");
  201.     return oldbit;
  202. }
  203. 原子的翻转addr所指对象的第nr位,并返回原先的值;

  204. to be continue ......

参考:
   《汇编语言程序设计》
   《linux内核设计实现》
    Linux 内核的同步机制,第 1 ,2部分
   http://www.ibm.com/developerworks/cn/linux/l-synch/part2/
   linux内存屏障浅析
    

 
阅读(521) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~