ARM原子操作atomic_add详解



ARM原子操作atomic_add详解

static inline void atomic_add(int i, atomic_t *v)

 {

     unsigned long tmp;

     int result;

    prefetchw(&v->counter); -------------------------(2

    __asm__ __volatile__("@ atomic_add\n" ------------------(3

"1:    ldrex    %0, [%3]\n" -----------------------(4"    add    %0, %0, %4\n" -----------------------(5

"    strex    %1, %0, [%3]\n" ----------------------(6

"    teq    %1, #0\n" -------------------------(7

"    bne    1b"

     : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ---对应%0,%1,%2

     : "r" (&v->counter), "Ir" (i) -------------对应%3

}

其中%3就是input operand list中的"r" (&v->counter)r是限制符(constraint),用来告诉编译器gcc,你看着办吧,你帮我选择一个通用寄存器保存该操作数吧。%0对应output openrand list中的"=&r" (result)=表示该操作数是write only的,&表示该操作数是一个earlyclobber operand,具体是什么意思呢?编译器在处理嵌入式汇编的时候,倾向使用尽可能少的寄存器,如果output operand没有&修饰的话,汇编指令中的inputoutput操作数会使用同样一个寄存器。因此,&确保了%3和%0使用不同的寄存器。

5)完成步骤(4)后,%0这个output操作数已经被赋值为atomic_t变量的old value,毫无疑问,这里的操作是要给old value加上i。这里%4对应"Ir" (i),这里“I”这个限制符对应ARM平台,表示这是一个有特定限制的立即数,该数必须是0255之间的一个整数通过rotation的操作得到的一个32bit的立即数。这是和ARMdata-processing instructions如何解析立即数有关的。每个指令32bit,其中12bit被用来表示立即数,其中8bit是真正的数据,4bit用来表示如何rotation。更详细的内容请参考ARM ARM文档。

6)这一步将修改后的new value保存在atomic_t变量中。是否能够正确的操作的状态标记保存在%1操作数中,也就是"=&r" (tmp)

7)检查memory update的操作是否正确完成,如果OK,皆大欢喜,如果发生了问题(有其他的内核路径插入),那么需要跳转到lable 1那里,从新进行一次read-modify-write的操作。

C中内嵌汇编详解:

http://www.360doc.com/content/15/0129/12/11400509_444690221.shtml

你可能感兴趣的:(LINUX内核)