在DPDK中遇到了一个内嵌C代码的函数,于是了解了一下其语法。
主要参考文档
static inline void
rte_spinlock_lock(rte_spinlock_t *sl)
{
int lock_val = 1;
asm volatile (
"1:\n"
"xchg %[locked], %[lv]\n"
"test %[lv], %[lv]\n"
"jz 3f\n"
"2:\n"
"pause\n"
"cmpl $0, %[locked]\n"
"jnz 2b\n"
"jmp 1b\n"
"3:\n"
: [locked] "=m" (sl->locked), [lv] "=q" (lock_val)
: "[lv]" (lock_val)
: "memory");
}
- 这是一段 extended asm(它与Basic asm的区别在于它有operand,即上述16~18行)。
- extended asm代码必须写在函数内,Basic asm不用。
extend asm主要有2种格式:
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
asm asm-qualifiers ( AssemblerTemplate
:
: InputOperands
: Clobbers
: GotoLabels)
上述代码使用的是后一种。
格式分析
-
volatile为asm-qualifier。
- volatile的作用为:防止assembler对asm代码进行优化,改变其原来的布局。
-
6~15行,为Assembler Template
- 它读取Operand中的输入,形成最终的汇编代码,并由gcc传给assembler解析。 gcc自己不会分析这段内容。
-
第16行,为Output Operands
- [locked] 和 [lv] 对应 Template 中的 %[locked] 和 %[lv]。
- (sl->locked) 和 (lock_val) 对应C代码中的变量。
- 汇编代码运行后的输出由这句代码指定。
-
Output Operands中的
"=m"
为 Constraints。- "="为Modifier,其表示用左边的值覆写右边的值。
-
m
为 simple constraint中的一个,表示将结果存放到内存中。 -
q
表示哪个寄存器本人尚未清楚。
-
第17行,为Input Operands,用于指定Template中的输入
-
第18行,为Clobber,用于指定汇编代码需要改变哪些寄存器/其他位置的数据,防止代码意外地改写更多数据。
- momory表示汇编代码会读或写内存到上述的Input/Output Operands
汇编内容分析
- 第6、10、15行为汇编中的Label,用于跳转用。第9、13、14会根据Condition Register的内容进行跳转。
3f
表示Label 3在下面,1b
和2b
表示Label 1和Label 2在上面。 - %[xxx] 对应Input/Output Operands中的变量。
- $0 表示数字0
-
test
对2个操作数进行AND操作。 - cmpl(Compare Logical),以unsigned integer的形式比较2个操作数的内容,并改写Condition Register Field中的一个bit。
- pause ,一般只用在Spinlock的代码中,用来告诉CPU接下来运行的代码是spin-wait循环。 具体细节貌似较为复杂,感兴趣的可以仔细浏览这两个链接。
此函数的目的就是加锁,即将sl->locked变量置为1.
- 输入值lv(即lock_val)为1,在第7行将 lv 与 locked 交换,并检查交换后 lv 的值。若为0,说明锁之前是free的,此时成功加锁,跳到 Label 3退出函数。
- 若交换后 lv 的值为1,说明锁已经被加上,这就需要等待其free后再加锁,10~13行即等待锁free的循环。
- 等到锁为free时,从14行跳到第6行,继续执行第1步。
网友评论