cmpxchgl
白天在公司看DPDK的代码,一个使用cmpxchgl指令实现的支持多生产者-多消费者的内存池,挺有意思的,里面有一处关键代码为rte_atomic32_cmp_set()(好像是这个名字?),其实现在Nginx代码内也有,现在家里电脑上没有DPDK的代码,所以就直接来看看Nginx内的具体实现:
static ngx_inline ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, ngx_atomic_uint_t set) { u_char res; __asm__ volatile ( NGX_SMP_LOCK " cmpxchgl %3, %1; " " sete %0; " : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); return res; }
这段代码来之ngx_gcc_atomic_x86.h,虽然其它文件,比如ngx_gcc_atomic_amd64.h也有,但基本一致,所以暂就以它为例。
要看懂这段代码,首先需对Linux下C中嵌入汇编有所了解,这可以关键字“GCC-Inline-Assembly-HOWTO”进行Google ,比如:http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html,简单介绍也就是嵌入汇编的基本格式为:
asm ( assembler template : output operands /* optional */ : input operands /* optional */ : list of clobbered registers /* optional */ );
因此对照来看,函数ngx_atomic_cmp_set()内:
汇编模板为两条或三条,因为宏NGX_SMP_LOCK展开可能为空(单核)或为”lock;”(多核);
输出操作数为res(对应的寄存器为eax,这里x86限定为32位系统,下同);
输入操作数为*lock(memory内存)、old(eax寄存器)、set(任意可用通用寄存器)
附带影响:cc表示标志寄存器会被附带修改、memory表示内存会被附带修改。
在汇编模板里,各个输入\输出操作数是以%0、%1、%2,…等进行指代的,因此汇编模板可展开为(用大括号括起来,以示区分):
lock; cmpxchgl {set}, {*lock}; sete {res};
第一条指令lock,表示锁定总线,这显然只有在多核情况下才有必要。
http://faydoc.tripod.com/cpu/lock.htm
第二条真实指令为cmpxchg,末尾的l表示操作数长度为4,这条指令有点复杂,它用到了一个隐含的操作数,即eax。在前面的输入操作数中,我们看到了old,其对应的%2却并没有在汇编模板里出现,但通过修饰符a把它存放到了eax寄存器,因此这里被cmpxchg指令隐含使用。
指令cmpxchg比较eax(也就是{old})与{*lock}的值,如果相等,那么将{set}的值赋值给{*lock},同时标志寄存器ZF位置1;否则,将{*lock}的值赋值给eax,并且将标志寄存器ZF位置0。
相关介绍在这:http://faydoc.tripod.com/cpu/cmpxchg.htm,但注意这里是以Intel汇编语法进行描述的,而Intel汇编语法与AT&T汇编的操作数位置是一个反的。
第三条指令sete,如果标志寄存器ZF位为1,那么设置{res}为1。
http://faydoc.tripod.com/cpu/sete.htm
http://web.itu.edu.tr/kesgin/mul06/intel/intel_flags.html
因此,整体下来,函数:
ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
ngx_atomic_uint_t set);
的含义就是:如果*lock值等于old,那么将set值赋值给*lock,并返回1。一般情况,lock表示一把锁,而old为其未被任何进程持有的情况,即为0,而set值为1,也就是这样的调用:ngx_atomic_cmp_set(lock, 0, 1)返回1则表示获取锁成功。
在DPDK的内存池里就是利用同样的东东来实现多用户(多生产者或多消费者)情况下修改环形缓冲区的队头或队尾指针:do {…} while ((success = rte_atomic32_cmp_set(r->head, old_head, new_head) == 0))。
转载请保留地址:http://lenky.info/archives/2012/11/17/2028 或 http://lenky.info/?p=2028
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。
写的很详细。 有新帖子weibo也发下吧。 发现好多帖子错过了