异想天开

What's the true meaning of light, Could you tell me why

nginx的原子性操作

日期:2017-01-31 10:28:57
  
最后更新日期:2017-01-31 10:48:31
在翻看代码时,看到原子性操作,而那处原子性代码写得烂。想起nginx里面也有对原子性操作的封装。
nginx源码路径src/os/unix/ngx_atomic.h里面通过宏封装了几种不同平台和编译器的原子操作:
宏NGX_HAVE_LIBATOMIC 表示使用libatomic库
宏NGX_DARWIN_ATOMIC 表示使用苹果平台的原子操作库
宏NGX_HAVE_GCC_ATOMIC 表示使用gcc 4.1以上版本的内置原子操作,如:
__sync_bool_compare_and_swap(lock, old, set)
__sync_fetch_and_add(value, add)
还通过宏封装了x86,amd64,powerpc等不同硬件平台的不同编译器下的汇编指令代码。
若上诉原子性操作不存在,则定义NGX_HAVE_ATOMIC_OP宏为0,将使用非原子性操作。

x86里面的gcc编译器实现如下:
[code lang="cpp"]
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;
}
[/code]
1. 相同的硬件平台里面汇编指令是一样的,但使用不同的编译器的写法会不一样。可以搜索下c语言里面嵌入汇编怎么写。

2. NGX_SMP_LOCK表示: 若为多核环境,则使用lock指令。否则为空。
#if (NGX_SMP)
#define NGX_SMP_LOCK "lock;"
#else
#define NGX_SMP_LOCK
#endif
使用lock指令,表示锁住总线, 在奔腾4以上的cpu,lock不一定会锁住总线,假设该地址被cpu cache住了,lock指令会锁住cache,而不去锁住总线。

3. cmpxchgl指令。nginx里面有用c语言的伪码:
[code lang="cpp"]
"cmpxchgl r, [m]":

if (eax == [m]) {
zf = 1;
[m] = r;
} else {
zf = 0;
eax = [m];
}
[/code]
r表示通用寄存器, zf表示零标志位,cc表示会破坏标志寄存器,memory表示会破坏内存。

4. sete指令。c语言的伪码:
[code lang="cpp"]
"sete r ":
if (zf == 1):
r = zf
[/code]
5. 翻看Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1。x86 cpu支持如下三种读写内存原子性操作:
a. 读写一个16位, 32位,64位地址对齐的内存
b. 锁住总线
c. 锁住 cpu cache
上诉通过lock指令,锁住总线 或cache实现了原子性修改。