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