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 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@245389 91177308-0d34-0410-b5e6-96231b3b80d8
110 lines
3.3 KiB
C++
110 lines
3.3 KiB
C++
#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
|