diff options
| author | Eric Fiselier <eric@efcs.ca> | 2015-08-18 23:29:59 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2015-08-18 23:29:59 +0000 |
| commit | 10967a6ea6a8b92ce18e37da77be48fe7f6f54d7 (patch) | |
| tree | accec306a4dfa89b01809c203a335f9f0a216115 /libcxx/test/support/test_atomic.h | |
| parent | d4c8f70ce182a5bf31ce697aba232b6541ff5450 (diff) | |
| download | bcm5719-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.h | 109 |
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 |

