Use __atomic_{load, store, compare_exchange}_n when USE_LOCKS is defined
using new macros atomic_load_acquire, atomic_store_release,
atomic_compare_exchange.  The new macros fall back to non-atomic operations
when USE_LOCKS is not defined.

Also use valgrind annotations in these macros.  Helgrind does not track
ordering of atomics so annotations may be needed to prevent false
positives.

Signed-off-by: Aaron Merey <[email protected]>

---
v2: add atomic_compare_exchange and valgrind annotations

 lib/locks.h    | 32 ++++++++++++++++++++++++++++++++
 libdw/libdwP.h | 16 ++++------------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/lib/locks.h b/lib/locks.h
index 9b303092..3771c201 100644
--- a/lib/locks.h
+++ b/lib/locks.h
@@ -29,6 +29,8 @@
 #ifndef LOCKS_H
 #define LOCKS_H     1
 
+#include <stdbool.h>
+
 #if USE_VG_ANNOTATIONS == 1
 # include <valgrind/helgrind.h>
 #else
@@ -64,6 +66,27 @@
 # define mutex_fini(lock)              MUTEX_CALL (destroy (&lock))
 # define once(once_control, init_routine)  \
   ONCE_CALL (once (&once_control, init_routine))
+/* __atomic_* compiler builtin functions are used instead of <stdatomic.h>
+   because the builtins can operate on non-_Atomic types.
+   Dwarf_Die.abbrev cannot be made _Atomic without possibly breaking ABI
+   compatibility.  Include valgrind annotations since helgrind does not
+   track ordering from atomics.  Values set with atomic_store_release but
+   loaded without a lock should also be annotated with
+   VALGRIND_HG_DISABLE_CHECKING.  */
+# define atomic_load_acquire(ptr) \
+  ({ __typeof__ (*(ptr)) _val = __atomic_load_n ((ptr), __ATOMIC_ACQUIRE);  \
+     ANNOTATE_HAPPENS_AFTER (ptr);                                         \
+     _val; })
+# define atomic_store_release(ptr, val)  \
+  ({ ANNOTATE_HAPPENS_BEFORE (ptr);     \
+     __atomic_store_n ((ptr), (val), __ATOMIC_RELEASE); })
+# define atomic_compare_exchange(ptr, expected, val) \
+  ({ ANNOTATE_HAPPENS_BEFORE (ptr);                                       \
+     bool _match = __atomic_compare_exchange_n ((ptr), (expected), (val),  \
+                                               false, __ATOMIC_RELEASE,   \
+                                               __ATOMIC_ACQUIRE);         \
+     ANNOTATE_HAPPENS_AFTER (ptr);                                        \
+     _match; })
 #else
 /* Eventually we will allow multi-threaded applications to use the
    libraries.  Therefore we will add the necessary locking although
@@ -81,6 +104,15 @@
 # define mutex_fini(lock) ((void) (lock))
 # define once_define(class,name)
 # define once(once_control, init_routine)       init_routine()
+# define atomic_load_acquire(ptr) (*(ptr))
+# define atomic_store_release(ptr, val) ((void) (*(ptr) = (val)))
+# define atomic_compare_exchange(ptr, expected, val) \
+  ({ bool _match = *(ptr) == *(expected);  \
+     if (_match)                          \
+       *(ptr) = (val);                    \
+     else                                 \
+       *(expected) = *(ptr);              \
+     _match; })
 #endif  /* USE_LOCKS */
 
 #endif  /* locks.h */
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 9e7e2339..982b9525 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -824,16 +824,11 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char 
**readp)
 
   if (unlikely (die->cu == NULL))
     {
-      /* __atomic_* compiler builtin functions are used instead of 
<stdatomic.h>
-        because the builtins can operate on non-_Atomic types.
-        Dwarf_Die.abbrev cannot be made _Atomic without possibly breaking ABI
-        compatibility.  */
-      __atomic_compare_exchange_n (&die->abbrev, &expected, end_abbrev, false,
-                                  __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+      atomic_compare_exchange (&die->abbrev, &expected, end_abbrev);
       return end_abbrev;
     }
 
-  Dwarf_Abbrev *abbrev = __atomic_load_n (&die->abbrev, __ATOMIC_ACQUIRE);
+  Dwarf_Abbrev *abbrev = atomic_load_acquire (&die->abbrev);
   if (abbrev == NULL || readp != NULL)
     {
       /* We need to get the abbreviation or need to read after the code.  */
@@ -841,9 +836,7 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char 
**readp)
       const unsigned char *addr = die->addr;
       if (addr >= (const unsigned char *) die->cu->endp)
        {
-         __atomic_compare_exchange_n (&die->abbrev, &expected,
-                                      end_abbrev, false,
-                                      __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+         atomic_compare_exchange (&die->abbrev, &expected, end_abbrev);
          return end_abbrev;
        }
 
@@ -856,8 +849,7 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char 
**readp)
       if (abbrev == NULL)
        {
          abbrev = __libdw_findabbrev (die->cu, code);
-         __atomic_compare_exchange_n (&die->abbrev, &expected, abbrev, false,
-                                      __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+         atomic_compare_exchange (&die->abbrev, &expected, abbrev);
        }
     }
 
-- 
2.55.0

Reply via email to