PR20546: Fix tests for compare_exchange_weak.
These calls are allowed to fail spuriously. 29.6.5.25: Remark: A weak compare-and-exchange operation may fail spuriously. That is, even when the contents of memory referred to by expected and object are equal, it may return false and store back to expected the same memory contents that were originally there. [ Note: This spurious failure enables implementation of compare and-exchange on a broader class of machines, e.g., load-locked store-conditional machines. A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop. To fix this, we replace any assert() that expects std::atomic::compare_exchange_weak() to return true with a loop. If the call does not return true within N runs (with N currently equal to 10), then the test fails. http://llvm.org/bugs/show_bug.cgi?id=20546 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@217319 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
baed05dd37
commit
7ba3c57565
@ -73,6 +73,8 @@
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include <cmpxchg_loop.h>
|
||||
|
||||
template <class A, class T>
|
||||
void
|
||||
do_test()
|
||||
@ -96,7 +98,7 @@ do_test()
|
||||
assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2));
|
||||
assert(obj == T(3));
|
||||
T x = obj;
|
||||
assert(obj.compare_exchange_weak(x, T(2)) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, T(2)) == true);
|
||||
assert(obj == T(2));
|
||||
assert(x == T(3));
|
||||
assert(obj.compare_exchange_weak(x, T(1)) == false);
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include <new>
|
||||
#include <cassert>
|
||||
|
||||
#include <cmpxchg_loop.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
@ -77,7 +79,7 @@ int main()
|
||||
assert(obj.exchange(true, std::memory_order_relaxed) == false);
|
||||
assert(obj == true);
|
||||
bool x = obj;
|
||||
assert(obj.compare_exchange_weak(x, false) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
assert(obj.compare_exchange_weak(x, true,
|
||||
@ -86,9 +88,9 @@ int main()
|
||||
assert(x == false);
|
||||
obj.store(true);
|
||||
x = true;
|
||||
assert(obj.compare_exchange_weak(x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
x = true;
|
||||
@ -132,7 +134,7 @@ int main()
|
||||
assert(obj.exchange(true, std::memory_order_relaxed) == false);
|
||||
assert(obj == true);
|
||||
bool x = obj;
|
||||
assert(obj.compare_exchange_weak(x, false) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
assert(obj.compare_exchange_weak(x, true,
|
||||
@ -141,9 +143,9 @@ int main()
|
||||
assert(x == false);
|
||||
obj.store(true);
|
||||
x = true;
|
||||
assert(obj.compare_exchange_weak(x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
x = true;
|
||||
@ -187,7 +189,7 @@ int main()
|
||||
assert(obj.exchange(true, std::memory_order_relaxed) == false);
|
||||
assert(obj == true);
|
||||
bool x = obj;
|
||||
assert(obj.compare_exchange_weak(x, false) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
assert(obj.compare_exchange_weak(x, true,
|
||||
@ -196,9 +198,9 @@ int main()
|
||||
assert(x == false);
|
||||
obj.store(true);
|
||||
x = true;
|
||||
assert(obj.compare_exchange_weak(x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, false,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_seq_cst) == true);
|
||||
assert(obj == false);
|
||||
assert(x == true);
|
||||
x = true;
|
||||
|
@ -90,6 +90,8 @@
|
||||
#include <new>
|
||||
#include <cassert>
|
||||
|
||||
#include <cmpxchg_loop.h>
|
||||
|
||||
template <class A, class T>
|
||||
void
|
||||
do_test()
|
||||
@ -112,7 +114,7 @@ do_test()
|
||||
assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2));
|
||||
assert(obj == T(3));
|
||||
T x = obj;
|
||||
assert(obj.compare_exchange_weak(x, T(2)) == true);
|
||||
assert(cmpxchg_weak_loop(obj, x, T(2)) == true);
|
||||
assert(obj == T(2));
|
||||
assert(x == T(3));
|
||||
assert(obj.compare_exchange_weak(x, T(1)) == false);
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include <cmpxchg_loop.h>
|
||||
|
||||
template <class T>
|
||||
void
|
||||
test()
|
||||
@ -33,7 +35,7 @@ test()
|
||||
A a;
|
||||
T t(T(1));
|
||||
std::atomic_init(&a, t);
|
||||
assert(std::atomic_compare_exchange_weak(&a, &t, T(2)) == true);
|
||||
assert(c_cmpxchg_weak_loop(&a, &t, T(2)) == true);
|
||||
assert(a == T(2));
|
||||
assert(t == T(1));
|
||||
assert(std::atomic_compare_exchange_weak(&a, &t, T(3)) == false);
|
||||
@ -45,7 +47,7 @@ test()
|
||||
volatile A a;
|
||||
T t(T(1));
|
||||
std::atomic_init(&a, t);
|
||||
assert(std::atomic_compare_exchange_weak(&a, &t, T(2)) == true);
|
||||
assert(c_cmpxchg_weak_loop(&a, &t, T(2)) == true);
|
||||
assert(a == T(2));
|
||||
assert(t == T(1));
|
||||
assert(std::atomic_compare_exchange_weak(&a, &t, T(3)) == false);
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include <cmpxchg_loop.h>
|
||||
|
||||
template <class T>
|
||||
void
|
||||
test()
|
||||
@ -36,7 +38,7 @@ test()
|
||||
A a;
|
||||
T t(T(1));
|
||||
std::atomic_init(&a, t);
|
||||
assert(std::atomic_compare_exchange_weak_explicit(&a, &t, T(2),
|
||||
assert(c_cmpxchg_weak_loop(&a, &t, T(2),
|
||||
std::memory_order_seq_cst, std::memory_order_seq_cst) == true);
|
||||
assert(a == T(2));
|
||||
assert(t == T(1));
|
||||
@ -50,7 +52,7 @@ test()
|
||||
volatile A a;
|
||||
T t(T(1));
|
||||
std::atomic_init(&a, t);
|
||||
assert(std::atomic_compare_exchange_weak_explicit(&a, &t, T(2),
|
||||
assert(c_cmpxchg_weak_loop(&a, &t, T(2),
|
||||
std::memory_order_seq_cst, std::memory_order_seq_cst) == true);
|
||||
assert(a == T(2));
|
||||
assert(t == T(1));
|
||||
|
51
test/support/cmpxchg_loop.h
Normal file
51
test/support/cmpxchg_loop.h
Normal file
@ -0,0 +1,51 @@
|
||||
#include <atomic>
|
||||
|
||||
template <class A, class T>
|
||||
bool cmpxchg_weak_loop(A& atomic, T& expected, T desired) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (atomic.compare_exchange_weak(expected, desired) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class A, class T>
|
||||
bool cmpxchg_weak_loop(A& atomic, T& expected, T desired,
|
||||
std::memory_order success,
|
||||
std::memory_order failure) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (atomic.compare_exchange_weak(expected, desired, success,
|
||||
failure) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class A, class T>
|
||||
bool c_cmpxchg_weak_loop(A* atomic, T* expected, T desired) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (std::atomic_compare_exchange_weak(atomic, expected, desired) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class A, class T>
|
||||
bool c_cmpxchg_weak_loop(A* atomic, T* expected, T desired,
|
||||
std::memory_order success,
|
||||
std::memory_order failure) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (std::atomic_compare_exchange_weak_explicit(atomic, expected, desired,
|
||||
success, failure) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
Loading…
Reference in New Issue
Block a user