summaryrefslogtreecommitdiffstats
path: root/libcxx/test/support/test_atomic.h
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2015-08-18 23:29:59 +0000
committerEric Fiselier <eric@efcs.ca>2015-08-18 23:29:59 +0000
commit10967a6ea6a8b92ce18e37da77be48fe7f6f54d7 (patch)
treeaccec306a4dfa89b01809c203a335f9f0a216115 /libcxx/test/support/test_atomic.h
parentd4c8f70ce182a5bf31ce697aba232b6541ff5450 (diff)
downloadbcm5719-llvm-10967a6ea6a8b92ce18e37da77be48fe7f6f54d7.tar.gz
bcm5719-llvm-10967a6ea6a8b92ce18e37da77be48fe7f6f54d7.zip
[libcxx] Add Atomic test helper and fix TSAN failures.
Summary: This patch attempts to fix the last 3 TSAN failures on the libc++ bot (http://lab.llvm.org:8011/builders/libcxx-libcxxabi-x86_64-linux-ubuntu-tsan/builds/143). This patch also adds a `Atomic` test type that can be used where `<atomic>` cannot. `wait.exception.pass.cpp` and `wait_for.exception.pass.cpp` were failing because the test replaced `std::terminate` with `std::exit`. `std::exit` would asynchronously run the TLS and static destructors and this would cause a race condition. See PR22606 and D8802 for more details. This is fixed by using `_Exit` to prevent cleanup. `notify_all_at_thread_exit.pass.cpp` exercises the same race condition but for different reasons. I fixed this test by manually joining the thread before beginning program termination. Reviewers: EricWF, mclow.lists Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D11046 llvm-svn: 245389
Diffstat (limited to 'libcxx/test/support/test_atomic.h')
-rw-r--r--libcxx/test/support/test_atomic.h109
1 files changed, 109 insertions, 0 deletions
diff --git a/libcxx/test/support/test_atomic.h b/libcxx/test/support/test_atomic.h
new file mode 100644
index 00000000000..13a0b20250a
--- /dev/null
+++ b/libcxx/test/support/test_atomic.h
@@ -0,0 +1,109 @@
+#ifndef SUPPORT_TEST_ATOMIC_H
+#define SUPPORT_TEST_ATOMIC_H
+
+// If the atomic memory order macros are defined then assume
+// the compiler supports the required atomic builtins.
+#if !defined(__ATOMIC_SEQ_CST)
+#define TEST_HAS_NO_ATOMICS
+#endif
+
+template <class ValType>
+class Atomic {
+ ValType value;
+ Atomic(Atomic const&);
+ Atomic& operator=(Atomic const&);
+ Atomic& operator=(Atomic const&) volatile;
+private:
+ enum {
+#if !defined(TEST_HAS_NO_ATOMICS)
+ AO_Relaxed = __ATOMIC_RELAXED,
+ AO_Seq = __ATOMIC_SEQ_CST
+#else
+ AO_Relaxed,
+ AO_Seq
+#endif
+ };
+ template <class Tp, class FromType>
+ static inline void atomic_store_imp(Tp* dest, FromType from, int order = AO_Seq) {
+#if !defined(TEST_HAS_NO_ATOMICS)
+ __atomic_store_n(dest, from, order);
+#else
+ *dest = from;
+#endif
+ }
+
+ template <class Tp>
+ static inline Tp atomic_load_imp(Tp* from, int order = AO_Seq) {
+#if !defined(TEST_HAS_NO_ATOMICS)
+ return __atomic_load_n(from, order);
+#else
+ return *from;
+#endif
+ }
+
+ template <class Tp, class AddType>
+ static inline Tp atomic_add_imp(Tp* val, AddType add, int order = AO_Seq) {
+#if !defined(TEST_HAS_NO_ATOMICS)
+ return __atomic_add_fetch(val, add, order);
+#else
+ return *val += add;
+#endif
+ }
+
+ template <class Tp>
+ static inline Tp atomic_exchange_imp(Tp* val, Tp other, int order = AO_Seq) {
+#if !defined(TEST_HAS_NO_ATOMICS)
+ return __atomic_exchange_n(val, other, order);
+#else
+ Tp old = *val;
+ *val = other;
+ return old;
+#endif
+ }
+public:
+ Atomic() : value(0) {}
+ Atomic(ValType x) : value(x) {}
+
+ ValType operator=(ValType val) {
+ atomic_store_imp(&value, val);
+ return val;
+ }
+
+ ValType operator=(ValType val) volatile {
+ atomic_store_imp(&value, val);
+ return val;
+ }
+
+ ValType load() const volatile { return atomic_load_imp(&value); }
+ void store(ValType val) volatile { atomic_store_imp(&value, val); }
+
+ ValType relaxedLoad() const volatile { return atomic_load_imp(&value, AO_Relaxed); }
+ void relaxedStore(ValType val) volatile { atomic_store_imp(&value, val, AO_Relaxed); }
+
+ ValType exchange(ValType other) volatile { return atomic_exchange_imp(&value, other); }
+ bool testAndSet() volatile { return atomic_exchange_imp(&value, 1); }
+ void clear() volatile { atomic_store_imp(&value, 0); }
+
+ operator ValType() const { return atomic_load_imp(&value); }
+ operator ValType() const volatile { return atomic_load_imp(&value); }
+
+ ValType operator+=(ValType val) { return atomic_add_imp(&value, val); }
+ ValType operator-=(ValType val) { return atomic_add_imp(&value, -val); }
+ ValType operator+=(ValType val) volatile { return atomic_add_imp(&value, val); }
+ ValType operator-=(ValType val) volatile { return atomic_add_imp(&value, -val); }
+
+ ValType operator++() { return *this += 1; }
+ ValType operator++(int) { return (*this += 1) - 1; }
+ ValType operator++() volatile { return *this += 1; }
+ ValType operator++(int) volatile { return (*this += 1) - 1; }
+
+ ValType operator--() { return *this -= 1; }
+ ValType operator--(int) { return (*this -= 1) + 1; }
+ ValType operator--() volatile { return *this -= 1; }
+ ValType operator--(int) volatile { return (*this -= 1) + 1; }
+};
+
+typedef Atomic<int> AtomicInt;
+typedef Atomic<bool> AtomicBool;
+
+#endif // SUPPORT_TEST_ATOMIC_H
OpenPOWER on IntegriCloud