diff options
Diffstat (limited to 'src/os/unix/ngx_gcc_atomic_amd64.h')
-rw-r--r-- | src/os/unix/ngx_gcc_atomic_amd64.h | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/os/unix/ngx_gcc_atomic_amd64.h b/src/os/unix/ngx_gcc_atomic_amd64.h new file mode 100644 index 000000000..07b2d50b5 --- /dev/null +++ b/src/os/unix/ngx_gcc_atomic_amd64.h @@ -0,0 +1,74 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#if (NGX_SMP) +#define NGX_SMP_LOCK "lock;" +#else +#define NGX_SMP_LOCK +#endif + + +/* + * "cmpxchgq r, [m]": + * + * if (rax == [m]) { + * zf = 1; + * [m] = r; + * } else { + * zf = 0; + * rax = [m]; + * } + * + * + * The "r" is any register, %rax (%r0) - %r16. + * The "=a" and "a" are the %rax register. Although we can return result + * in any register, we use %rax because it is used in cmpxchgq anyway. + * The "cc" means that flags were changed. + */ + +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) +{ + ngx_atomic_uint_t res; + + __asm__ volatile ( + + NGX_SMP_LOCK + " cmpxchgq %3, %1; " + " setz %b0; " + " movzbq %b0, %0; " + + : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); + + return res; +} + + +/* + * "xaddq r, [m]": + * + * temp = [m]; + * [m] += r; + * r = temp; + * + * + * The "+r" is any register, %rax (%r0) - %r16. + * The "cc" means that flags were changed. + */ + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + __asm__ volatile ( + + NGX_SMP_LOCK + " xaddq %0, %1; " + + : "+q" (add) : "m" (*value) : "cc", "memory"); + + return add; +} |