-
/*
-
* atomic_add - add integer to atomic variable
-
* @i: integer value to add
-
* @v: pointer of type atomic_t
-
*
-
* Atomically adds @i to @v.
-
*/
-
static __inline__ void atomic_add(int i, atomic_t * v)
-
{
-
if (cpu_has_llsc && R10000_LLSC_WAR) {
-
int temp;
-
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_add \n"
-
" addu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqzl %0, 1b \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else if (cpu_has_llsc) {
-
int temp;
-
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_add \n"
-
" addu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqz %0, 2f \n"
-
" .subsection 2 \n"
-
"2: b 1b \n"
-
" .previous \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else {
-
unsigned long flags;
-
-
raw_local_irq_save(flags);
-
v->counter += i;
-
raw_local_irq_restore(flags);
-
}
-
}
在我的系统上,使用的是中间那段代码,看懂这段代码需要了解如下3个方面的知识:
-
mips架构下C语言内嵌汇编语言的格式;
-
mips下ll和sc指令的用法;
-
.subsection和.previous指令的用法。
下面分别介绍相关的知识:
asm (
"assembly code"
: output_operand /* 输出参数列表 */
: input_operand /* 输入参数列表 */
: clobbered_operand /* 被改变的操作对象列表 */
);
gcc内嵌汇编扩展格式如上所示,依次分别为汇编代码,输出参数列表,输入参数列表,被改变的操作列表。所有项目都是可选的(汇编代码为空的例子:barrier指令),atomic_add函数没有最后一项,最后一项的意思是告诉gcc,在汇编代码中除了可能会修改输入和输出参数,还会修改其他参数,以免gcc误判。
汇编代码中的%0,%1,%2表示从输出参数开始,按顺序给所有参数的标号,这里temp就是%0, v->counter为%1, i为%2。另外还有很多符号,r表示寄存器(temp经过r修饰,存入寄存器中),m表示内存,=,&等在都有描述。
这2条指令的用法在see mips run中的8.5.2节有详细描述,需要注意的是,如果能保证原子操作,那么sc指令成功,%0被置为1,如果不能,则sc指令执行失败,%0被转为0,所以代码中通过判断%0是否为0来决定是否需要跳转到2f处进而跳转到1b处重复atomic_add操作。
-
.subsection和.previous指令的用法
个人理解,.subsection和.previous是成对出现的,两者中间的代码会被存放到另外的代码段中,也就是说,
当beqz %0, 2f不跳转到2时,它的后一条指令不是2: b 1b,而是直接返回。
阅读(3327) | 评论(0) | 转发(0) |