[PATCH 2 of 2] Core: add ngx_atomic_store() and ngx_atomic_load()

Maxim Dounin mdounin at mdounin.ru
Sat Sep 17 06:59:20 UTC 2016


Hello!

On Fri, Sep 16, 2016 at 02:43:49PM -0700, Piotr Sikora wrote:

> Hey Maxim,
> 
> > The "*(lock) == 0" check here is just an optimization, it only
> > ensures that the lock is likely to succed.
> 
> Yes, and use of the ngx_atomic_load() doesn't affect that.
> 
> Namely, in the micro-benchmarks I did (heavy contention - 100 threads
> trying to acquire lock, update value, release lock in a loop), there
> is no performance lose while using ngx_atomic_load() on x86_64,
> whereas removing this optimization resulted in 3x worse performance.

The question is: why ngx_atomic_load() is at all needed.  For now 
the only reason I see is "because ThreadSanitizer complains".

> > If the
> > check returns a wrong result due to non-atomic load - this won't
> > do any harm.
> 
> It's not just wrong result but a "data race", which leads to undefined
> behavior (at least according to C++11).

As far as I understand, from C11 point of view undefined behaviour 
is still here even with ngx_atomic_load(), as it's not an atomic 
operation defined by C11.

I can understand introducing load/store as a part of introducing 
C11 atomic operations support.  But I see no reason why it should 
be done separately.

On the other hand, C11 doesn't seem to require explicit use of 
load/store operations, "*(lock)" will work just fine, though 
probably will not be optimal.

Just for the record, below is a quick-and-dirty patch to introduce 
С11 atomic operations support (mostly untested).

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1474094645 -10800
#      Sat Sep 17 09:44:05 2016 +0300
# Node ID b79d4fd920eaa056103f68d311452b8cd6da833c
# Parent  9a4934f07bb47fbcf154ce275a04eb5dd1ba16be
C11 atomic operations.

diff --git a/auto/cc/conf b/auto/cc/conf
--- a/auto/cc/conf
+++ b/auto/cc/conf
@@ -178,6 +178,27 @@ if [ "$NGX_PLATFORM" != win32 ]; then
     fi
 
 
+    ngx_feature="C11 atomic operations"
+    ngx_feature_name=NGX_HAVE_C11_ATOMIC
+    ngx_feature_run=yes
+    ngx_feature_incs="#include <stdatomic.h>"
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test="#ifndef ATOMIC_LONG_LOCK_FREE
+                      #error atomic_long is not lock-free
+                      #endif
+                      atomic_long  n = ATOMIC_VAR_INIT(0);
+                      long         tmp = 0;
+                      if (!atomic_compare_exchange_strong(&n, &tmp, 1))
+                          return 1;
+                      if (atomic_fetch_add(&n, 1) != 1)
+                          return 1;
+                      if (atomic_load(&n) != 2)
+                          return 1;
+                      atomic_thread_fence(memory_order_acq_rel);"
+    . auto/feature
+
+
     ngx_feature="gcc builtin atomic operations"
     ngx_feature_name=NGX_HAVE_GCC_ATOMIC
     ngx_feature_run=yes
diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -88,6 +88,44 @@ typedef uint32_t                    ngx_
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
 
 
+#elif (NGX_HAVE_C11_ATOMIC)
+
+/* C11 atomic operations */
+
+#include <stdatomic.h>
+
+#define NGX_HAVE_ATOMIC_OPS  1
+
+typedef long                        ngx_atomic_int_t;
+typedef unsigned long               ngx_atomic_uint_t;
+
+#if (NGX_PTR_SIZE == 8)
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
+#else
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
+#endif
+
+typedef volatile atomic_ulong       ngx_atomic_t;
+
+ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+    ngx_atomic_uint_t set)
+{
+    return atomic_compare_exchange_strong(lock, &old, set);
+}
+
+#define ngx_atomic_fetch_add(value, add)                                      \
+    atomic_fetch_add(value, add)
+
+#define ngx_memory_barrier()        atomic_thread_fence(memory_order_seq_cst)
+
+#if ( __i386__ || __i386 || __amd64__ || __amd64 )
+#define ngx_cpu_pause()             __asm__ ("pause")
+#else
+#define ngx_cpu_pause()
+#endif
+
+
 #elif (NGX_HAVE_GCC_ATOMIC)
 
 /* GCC 4.1 builtin atomic operations */

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list