-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Fix bug in atomic_ref's calculation of lock_free-ness. #93427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5394683
1bfc10f
f0d6bbf
bf36a36
c8bd1b5
d4c2c26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -11,9 +11,104 @@ | |||||||||
|
||||||||||
#include <cassert> | ||||||||||
#include <cstdint> | ||||||||||
#include <cstddef> | ||||||||||
#include <type_traits> | ||||||||||
|
||||||||||
#include "test_macros.h" | ||||||||||
|
||||||||||
#if defined(TEST_COMPILER_CLANG) | ||||||||||
# define TEST_ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE | ||||||||||
#elif defined(TEST_COMPILER_GCC) | ||||||||||
# define TEST_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE | ||||||||||
# define TEST_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE | ||||||||||
#elif TEST_COMPILER_MSVC | ||||||||||
// This is lifted from STL/stl/inc/atomic on github for the purposes of | ||||||||||
// keeping the tests compiling for MSVC's STL. It's not a perfect solution | ||||||||||
// but at least the tests will keep running. | ||||||||||
// | ||||||||||
// Note MSVC's STL never produces a type that is sometimes lock free, but not always lock free. | ||||||||||
template <class T, size_t Size = sizeof(T)> | ||||||||||
constexpr bool msvc_is_lock_free_macro_value() { | ||||||||||
return (Size <= 8 && (Size & Size - 1) == 0) ? 2 : 0; | ||||||||||
} | ||||||||||
# define TEST_ATOMIC_CHAR_LOCK_FREE ::msvc_is_lock_free_macro_value<char>() | ||||||||||
# define TEST_ATOMIC_SHORT_LOCK_FREE ::msvc_is_lock_free_macro_value<short>() | ||||||||||
# define TEST_ATOMIC_INT_LOCK_FREE ::msvc_is_lock_free_macro_value<int>() | ||||||||||
# define TEST_ATOMIC_LONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long>() | ||||||||||
# define TEST_ATOMIC_LLONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long long>() | ||||||||||
# define TEST_ATOMIC_POINTER_LOCK_FREE ::msvc_is_lock_free_macro_value<void*>() | ||||||||||
#else | ||||||||||
# error "Unknown compiler" | ||||||||||
#endif | ||||||||||
|
||||||||||
#ifdef TEST_COMPILER_CLANG | ||||||||||
# pragma clang diagnostic push | ||||||||||
# pragma clang diagnostic ignored "-Wc++11-extensions" | ||||||||||
#endif | ||||||||||
// The entire LockFreeStatus/LockFreeStatusEnum/LockFreeStatusType exists entirely to work around the support | ||||||||||
// for C++03, which many of our atomic tests run under. This is a bit of a hack, but it's the best we can do. | ||||||||||
// | ||||||||||
// We could limit the testing involving these things to C++11 or greater? But test coverage in C++03 seems important too. | ||||||||||
|
||||||||||
enum class LockFreeStatus : int { unknown = -1, never = 0, sometimes = 1, always = 2 }; | ||||||||||
#define COMPARE_TYPES(T1, T2) (sizeof(T1) == sizeof(T2) && TEST_ALIGNOF(T1) >= TEST_ALIGNOF(T2)) | ||||||||||
dalg24 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
template <class T> | ||||||||||
struct LockFreeStatusInfo { | ||||||||||
static const LockFreeStatus value = LockFreeStatus( | ||||||||||
COMPARE_TYPES(T, char) | ||||||||||
? TEST_ATOMIC_CHAR_LOCK_FREE | ||||||||||
: (COMPARE_TYPES(T, short) | ||||||||||
? TEST_ATOMIC_SHORT_LOCK_FREE | ||||||||||
: (COMPARE_TYPES(T, int) | ||||||||||
? TEST_ATOMIC_INT_LOCK_FREE | ||||||||||
: (COMPARE_TYPES(T, long) | ||||||||||
? TEST_ATOMIC_LONG_LOCK_FREE | ||||||||||
: (COMPARE_TYPES(T, long long) | ||||||||||
? TEST_ATOMIC_LLONG_LOCK_FREE | ||||||||||
: (COMPARE_TYPES(T, void*) ? TEST_ATOMIC_POINTER_LOCK_FREE : -1)))))); | ||||||||||
|
||||||||||
static const bool status_known = LockFreeStatusInfo::value != LockFreeStatus::unknown; | ||||||||||
}; | ||||||||||
|
||||||||||
// IDK why this blows up in C++03, but it does. So we'll just disable it. | ||||||||||
ldionne marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
#if TEST_STD_VER >= 11 | ||||||||||
static_assert(LockFreeStatusInfo<char>::status_known, ""); | ||||||||||
static_assert(LockFreeStatusInfo<short>::status_known, ""); | ||||||||||
static_assert(LockFreeStatusInfo<int>::status_known, ""); | ||||||||||
static_assert(LockFreeStatusInfo<long>::status_known, ""); | ||||||||||
static_assert(LockFreeStatusInfo<long long>::status_known, ""); | ||||||||||
static_assert(LockFreeStatusInfo<void*>::status_known, ""); | ||||||||||
|
||||||||||
// I think these are always supposed to be lock free, and it's worth trying to hardcode expected values. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want these assertions both in that helper file and the ones in the atomic_ref is_always_lock_free test? llvm-project/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp Lines 55 to 58 in d4c2c26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I do. Part of the point of this test facility is it provides known & expected value for what has previously been considered unknowable since it's architecture specific. These assertions are meant to establish that there are atomic operations on all CPU's we support. |
||||||||||
static_assert(LockFreeStatusInfo<char>::value == LockFreeStatus::always, ""); | ||||||||||
static_assert(LockFreeStatusInfo<short>::value == LockFreeStatus::always, ""); | ||||||||||
static_assert(LockFreeStatusInfo<int>::value == LockFreeStatus::always, | ||||||||||
""); // This one may not always be lock free, but we'll let the CI decide. | ||||||||||
#endif | ||||||||||
|
||||||||||
// These macros are somewhat suprising to use, since they take the values 0, 1, or 2. | ||||||||||
// To make the tests clearer, get rid of them in preference of AtomicInfo. | ||||||||||
ldionne marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
#undef TEST_ATOMIC_CHAR_LOCK_FREE | ||||||||||
#undef TEST_ATOMIC_SHORT_LOCK_FREE | ||||||||||
#undef TEST_ATOMIC_INT_LOCK_FREE | ||||||||||
#undef TEST_ATOMIC_LONG_LOCK_FREE | ||||||||||
#undef TEST_ATOMIC_LLONG_LOCK_FREE | ||||||||||
#undef TEST_ATOMIC_POINTER_LOCK_FREE | ||||||||||
|
||||||||||
#ifdef TEST_COMPILER_CLANG | ||||||||||
# pragma clang diagnostic pop | ||||||||||
#endif | ||||||||||
|
||||||||||
struct UserAtomicType { | ||||||||||
int i; | ||||||||||
|
||||||||||
|
@@ -64,6 +159,17 @@ struct LargeUserAtomicType { | |||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
template <template <class TestArg> class TestFunctor> | ||||||||||
struct TestEachLockFreeKnownIntegralType { | ||||||||||
void operator()() const { | ||||||||||
TestFunctor<char>()(); | ||||||||||
TestFunctor<short>()(); | ||||||||||
TestFunctor<int>()(); | ||||||||||
TestFunctor<long long>()(); | ||||||||||
TestFunctor<void*>()(); | ||||||||||
} | ||||||||||
}; | ||||||||||
|
||||||||||
ldionne marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
template <template <class TestArg> class TestFunctor> | ||||||||||
struct TestEachIntegralType { | ||||||||||
void operator()() const { | ||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.