From 4fddd84e831d32d4be7b7caf54f8389e4978091f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 4 Apr 2020 00:18:47 +0300 Subject: [PATCH 01/15] Extract simple part from #593 to have it earlier --- stl/inc/atomic | 35 +++++++++++++++++++ stl/inc/yvals_core.h | 6 ++-- .../VSO_0157762_feature_test_macros/test.cpp | 28 +++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 1ce5172cabd..3d0cea83b8d 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1970,11 +1970,27 @@ using atomic_ptrdiff_t = atomic; using atomic_intmax_t = atomic; using atomic_uintmax_t = atomic; +#if _HAS_CXX20 +// Though there are CMPXCHG8B and CMPXCHG16B, +// the largest atomics with a full set of efficient operations are pointer-sized. +using atomic_signed_lock_free = atomic_intptr_t; +using atomic_unsigned_lock_free = atomic_uintptr_t; +#endif // _HAS_CXX20 // STRUCT atomic_flag #define ATOMIC_FLAG_INIT \ {} struct atomic_flag { // flag with test-and-set semantics +#if _HAS_CXX20 + _NODISCARD bool test(const memory_order _Order = memory_order::seq_cst) const noexcept { + return _Storage.load(_Order) != 0; + } + + _NODISCARD bool test(const memory_order _Order = memory_order::seq_cst) const volatile noexcept { + return _Storage.load(_Order) != 0; + } +#endif // _HAS_CXX20 + bool test_and_set(const memory_order _Order = memory_order_seq_cst) noexcept { return _Storage.exchange(true, _Order) != 0; } @@ -2002,6 +2018,25 @@ struct atomic_flag { // flag with test-and-set semantics // atomic_flag NONMEMBERS +#if _HAS_CXX20 +inline bool atomic_flag_test(const volatile atomic_flag* const _Flag) noexcept { + return _Flag->test(); +} + +_NODISCARD inline bool atomic_flag_test(const atomic_flag* const _Flag) noexcept { + return _Flag->test(); +} + +_NODISCARD inline bool atomic_flag_test_explicit( + const volatile atomic_flag* const _Flag, const memory_order _Order) noexcept { + return _Flag->test(_Order); +} + +_NODISCARD inline bool atomic_flag_test_explicit(const atomic_flag* const _Flag, const memory_order _Order) noexcept { + return _Flag->test(_Order); +} +#endif // _HAS_CXX20 + inline bool atomic_flag_test_and_set(atomic_flag* _Flag) noexcept { return _Flag->test_and_set(); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index af8b115c858..cd18e9c2241 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1082,8 +1082,10 @@ #define __cpp_lib_atomic_value_initialization 201911L #if _HAS_CXX20 -#define __cpp_lib_atomic_float 201711L -#define __cpp_lib_bind_front 201907L +#define __cpp_lib_atomic_flag_test 201907L +#define __cpp_lib_atomic_float 201711L +#define __cpp_lib_atomic_lock_free_type_aliases 201907L +#define __cpp_lib_bind_front 201907L #ifndef __EDG__ // TRANSITION, VSO-1041044 #define __cpp_lib_bit_cast 201806L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index 2a7a4f5afc8..0d12f71811a 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -748,6 +748,20 @@ STATIC_ASSERT(__cpp_lib_array_constexpr == 201803L); STATIC_ASSERT(__cpp_lib_as_const == 201510L); #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_atomic_flag_test +#error __cpp_lib_atomic_flag_test is not defined +#elif __cpp_lib_atomic_flag_test != 201907L +#error __cpp_lib_atomic_flag_test is not 201907L +#else +STATIC_ASSERT(__cpp_lib_atomic_flag_test == 201907L); +#endif +#else +#ifdef __cpp_lib_atomic_flag_test +#error __cpp_lib_atomic_flag_test is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_atomic_float #error __cpp_lib_atomic_float is not defined @@ -776,6 +790,20 @@ STATIC_ASSERT(__cpp_lib_atomic_is_always_lock_free == 201603L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_atomic_lock_free_type_aliases +#error __cpp_lib_atomic_lock_free_type_aliases is not defined +#elif __cpp_lib_atomic_lock_free_type_aliases != 201907L +#error __cpp_lib_atomic_lock_free_type_aliases is not 201907L +#else +STATIC_ASSERT(__cpp_lib_atomic_lock_free_type_aliases == 201907L); +#endif +#else +#ifdef __cpp_lib_atomic_lock_free_type_aliases +#error __cpp_lib_atomic_lock_free_type_aliases is defined +#endif +#endif + #ifndef __cpp_lib_atomic_value_initialization #error __cpp_lib_atomic_value_initialization is not defined #elif __cpp_lib_atomic_value_initialization != 201911L From d517d284d013d5e22e638545b967031cc8b78073 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 4 Apr 2020 00:59:02 +0300 Subject: [PATCH 02/15] missing _NODISCARD --- stl/inc/atomic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 3d0cea83b8d..2e5de8b8270 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -2019,7 +2019,7 @@ struct atomic_flag { // flag with test-and-set semantics // atomic_flag NONMEMBERS #if _HAS_CXX20 -inline bool atomic_flag_test(const volatile atomic_flag* const _Flag) noexcept { +_NODISCARD inline bool atomic_flag_test(const volatile atomic_flag* const _Flag) noexcept { return _Flag->test(); } From 3ae2c0a5005aaaeb1b8ec29eb4a817fc79c7d92a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 10 Apr 2020 08:12:22 +0300 Subject: [PATCH 03/15] Add test --- tests/tr1/tests/atomic/test.cpp | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/tr1/tests/atomic/test.cpp b/tests/tr1/tests/atomic/test.cpp index 993cf76db3b..4dec998148c 100644 --- a/tests/tr1/tests/atomic/test.cpp +++ b/tests/tr1/tests/atomic/test.cpp @@ -223,6 +223,60 @@ static void test_atomic_flag() { // test properties of atomic_flag CHECK_INT(value, false); } +#if _HAS_CXX20 +// TEST C++20 SEMANTICS OF atomic_flag +static void test_atomic_flag_cxx20() { // test properties of atomic_flag + STD atomic_flag flag = ATOMIC_FLAG_INIT; + bool value = flag.test(); + CHECK_INT(value, false); + value = flag.test(); + CHECK_INT(value, false); + value = flag.test_and_set(STD memory_order_acq_rel); + CHECK_INT(value, false); + value = flag.test(STD memory_order_acquire); + CHECK_INT(value, true); + flag.clear(); + value = flag.test(); + CHECK_INT(value, false); + value = flag.test_and_set(); + CHECK_INT(value, false); + value = flag.test(); + CHECK_INT(value, true); + flag.clear(STD memory_order_release); + value = flag.test_and_set(); + CHECK_INT(value, false); + value = flag.test(STD memory_order_acquire); + CHECK_INT(value, true); + + volatile STD atomic_flag vflag = ATOMIC_FLAG_INIT; + value = vflag.test(STD memory_order_relaxed); + CHECK_INT(value, false); + value = vflag.test_and_set(STD memory_order_release); + CHECK_INT(value, false); + value = vflag.test_and_set(STD memory_order_release); + CHECK_INT(value, true); + value = vflag.test(STD memory_order_acquire); + CHECK_INT(value, true); + vflag.clear(); + value = vflag.test_and_set(); + CHECK_INT(value, false); + flag.clear(STD memory_order_relaxed); + value = flag.test_and_set(); + CHECK_INT(value, false); + + value = STD atomic_flag_test_and_set(&flag); + CHECK_INT(value, true); + STD atomic_flag_clear(&flag); + value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_relaxed); + CHECK_INT(value, false); + value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_release); + CHECK_INT(value, true); + STD atomic_flag_clear_explicit(&flag, STD memory_order_release); + value = STD atomic_flag_test_and_set(&flag); + CHECK_INT(value, false); +} +#endif // _HAS_CXX20 + // TEST SEMANTICS OF ATOMIC TYPES template struct values { @@ -770,6 +824,21 @@ static void test_typedefs() { // test that atomic typedefs exist CHECK_TYPE(STD atomic_intmax_t, STD atomic); CHECK_TYPE(STD atomic_uintmax_t, STD atomic); } + +#if _HAS_CXX20 +static void test_lock_free_types() { + STD atomic_signed_lock_free signed_lf; + CHECK_TYPE(signed_lf.is_lock_free(), true); + volatile STD atomic_signed_lock_free vsigned_lf; + CHECK_TYPE(vsigned_lf.is_lock_free(), true); + STD atomic_unsigned_lock_free unsigned_lf; + CHECK_TYPE(unsigned_lf.is_lock_free(), true); + volatile STD atomic_unsigned_lock_free vunsigned_lf; + CHECK_TYPE(vunsigned_lf.is_lock_free(), true); + static_assert(STD atomic_signed_lock_free::is_always_lock_free); + static_assert(STD atomic_unsigned_lock_free::is_always_lock_free); +} +#endif // _HAS_CXX20 // RUN TESTS void test_main() { // test header test_memory_order_enum(); @@ -795,4 +864,8 @@ void test_main() { // test header test_atomic_udt(); test_fences(); test_typedefs(); +#if _HAS_CXX20 + test_atomic_flag_cxx20(); + test_lock_free_types(); +#endif } From f2e5be53a99cc205587d3fd2b3b8480caafca785 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 10 Apr 2020 16:07:12 +0300 Subject: [PATCH 04/15] a bit more smoke tests --- tests/tr1/tests/atomic/test.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/tr1/tests/atomic/test.cpp b/tests/tr1/tests/atomic/test.cpp index 4dec998148c..108ae07a7ac 100644 --- a/tests/tr1/tests/atomic/test.cpp +++ b/tests/tr1/tests/atomic/test.cpp @@ -263,17 +263,29 @@ static void test_atomic_flag_cxx20() { // test properties of atomic_flag flag.clear(STD memory_order_relaxed); value = flag.test_and_set(); CHECK_INT(value, false); + value = flag.test(STD memory_order_acquire); + CHECK_INT(value, true); + value = STD atomic_flag_test(&flag); + CHECK_INT(value, true); value = STD atomic_flag_test_and_set(&flag); CHECK_INT(value, true); + value = STD atomic_flag_test(&flag); + CHECK_INT(value, true); STD atomic_flag_clear(&flag); value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_relaxed); CHECK_INT(value, false); + value = STD atomic_flag_test_explicit(&flag, STD memory_order_relaxed); + CHECK_INT(value, true); value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_release); CHECK_INT(value, true); + value = STD atomic_flag_test_explicit(&flag, STD memory_order_relaxed); + CHECK_INT(value, true); STD atomic_flag_clear_explicit(&flag, STD memory_order_release); value = STD atomic_flag_test_and_set(&flag); CHECK_INT(value, false); + value = STD atomic_flag_test_explicit(&flag, STD memory_order_acquire); + CHECK_INT(value, true); } #endif // _HAS_CXX20 From a783c22cf2099621cd4577f8a9d139d3cd4ef97f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 10 Apr 2020 17:37:46 +0300 Subject: [PATCH 05/15] fix incorrect merge --- tests/std/tests/VSO_0157762_feature_test_macros/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index 13d221c9c78..1e6131a18a8 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -815,6 +815,7 @@ STATIC_ASSERT(__cpp_lib_atomic_lock_free_type_aliases == 201907L); #endif #endif +#if _HAS_CXX20 #ifndef __cpp_lib_atomic_shared_ptr #error __cpp_lib_atomic_shared_ptr is not defined #elif __cpp_lib_atomic_shared_ptr != 201711L From ec1fcade8256ded907fd809324cf62dcbf3b6a5d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 06:05:27 +0300 Subject: [PATCH 06/15] Update tests/tr1/tests/atomic/test.cpp Co-Authored-By: Casey Carter --- tests/tr1/tests/atomic/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tr1/tests/atomic/test.cpp b/tests/tr1/tests/atomic/test.cpp index 756ba114b48..142a4e416a7 100644 --- a/tests/tr1/tests/atomic/test.cpp +++ b/tests/tr1/tests/atomic/test.cpp @@ -225,7 +225,7 @@ static void test_atomic_flag() { // test properties of atomic_flag #if _HAS_CXX20 // TEST C++20 SEMANTICS OF atomic_flag static void test_atomic_flag_cxx20() { // test properties of atomic_flag - STD atomic_flag flag = ATOMIC_FLAG_INIT; + STD atomic_flag flag; bool value = flag.test(); CHECK_INT(value, false); value = flag.test(); From 35e5ca3c941f28321678049efa5c1721fa272def Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 06:05:34 +0300 Subject: [PATCH 07/15] Update tests/tr1/tests/atomic/test.cpp Co-Authored-By: Casey Carter --- tests/tr1/tests/atomic/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tr1/tests/atomic/test.cpp b/tests/tr1/tests/atomic/test.cpp index 142a4e416a7..642895ca234 100644 --- a/tests/tr1/tests/atomic/test.cpp +++ b/tests/tr1/tests/atomic/test.cpp @@ -247,7 +247,7 @@ static void test_atomic_flag_cxx20() { // test properties of atomic_flag value = flag.test(STD memory_order_acquire); CHECK_INT(value, true); - volatile STD atomic_flag vflag = ATOMIC_FLAG_INIT; + volatile STD atomic_flag vflag; value = vflag.test(STD memory_order_relaxed); CHECK_INT(value, false); value = vflag.test_and_set(STD memory_order_release); From 775eb0da43044466dcd1f51baff42eb80aa43665 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 20:06:03 +0300 Subject: [PATCH 08/15] Revert "Add test" This reverts commit 3ae2c0a5005aaaeb1b8ec29eb4a817fc79c7d92a. # Conflicts: # tests/tr1/tests/atomic/test.cpp --- tests/tr1/tests/atomic/test.cpp | 85 --------------------------------- 1 file changed, 85 deletions(-) diff --git a/tests/tr1/tests/atomic/test.cpp b/tests/tr1/tests/atomic/test.cpp index 756ba114b48..13801a350f1 100644 --- a/tests/tr1/tests/atomic/test.cpp +++ b/tests/tr1/tests/atomic/test.cpp @@ -222,72 +222,6 @@ static void test_atomic_flag() { // test properties of atomic_flag CHECK_INT(value, false); } -#if _HAS_CXX20 -// TEST C++20 SEMANTICS OF atomic_flag -static void test_atomic_flag_cxx20() { // test properties of atomic_flag - STD atomic_flag flag = ATOMIC_FLAG_INIT; - bool value = flag.test(); - CHECK_INT(value, false); - value = flag.test(); - CHECK_INT(value, false); - value = flag.test_and_set(STD memory_order_acq_rel); - CHECK_INT(value, false); - value = flag.test(STD memory_order_acquire); - CHECK_INT(value, true); - flag.clear(); - value = flag.test(); - CHECK_INT(value, false); - value = flag.test_and_set(); - CHECK_INT(value, false); - value = flag.test(); - CHECK_INT(value, true); - flag.clear(STD memory_order_release); - value = flag.test_and_set(); - CHECK_INT(value, false); - value = flag.test(STD memory_order_acquire); - CHECK_INT(value, true); - - volatile STD atomic_flag vflag = ATOMIC_FLAG_INIT; - value = vflag.test(STD memory_order_relaxed); - CHECK_INT(value, false); - value = vflag.test_and_set(STD memory_order_release); - CHECK_INT(value, false); - value = vflag.test_and_set(STD memory_order_release); - CHECK_INT(value, true); - value = vflag.test(STD memory_order_acquire); - CHECK_INT(value, true); - vflag.clear(); - value = vflag.test_and_set(); - CHECK_INT(value, false); - flag.clear(STD memory_order_relaxed); - value = flag.test_and_set(); - CHECK_INT(value, false); - value = flag.test(STD memory_order_acquire); - CHECK_INT(value, true); - - value = STD atomic_flag_test(&flag); - CHECK_INT(value, true); - value = STD atomic_flag_test_and_set(&flag); - CHECK_INT(value, true); - value = STD atomic_flag_test(&flag); - CHECK_INT(value, true); - STD atomic_flag_clear(&flag); - value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_relaxed); - CHECK_INT(value, false); - value = STD atomic_flag_test_explicit(&flag, STD memory_order_relaxed); - CHECK_INT(value, true); - value = STD atomic_flag_test_and_set_explicit(&flag, STD memory_order_release); - CHECK_INT(value, true); - value = STD atomic_flag_test_explicit(&flag, STD memory_order_relaxed); - CHECK_INT(value, true); - STD atomic_flag_clear_explicit(&flag, STD memory_order_release); - value = STD atomic_flag_test_and_set(&flag); - CHECK_INT(value, false); - value = STD atomic_flag_test_explicit(&flag, STD memory_order_acquire); - CHECK_INT(value, true); -} -#endif // _HAS_CXX20 - // TEST SEMANTICS OF ATOMIC TYPES template struct values { @@ -835,21 +769,6 @@ static void test_typedefs() { // test that atomic typedefs exist CHECK_TYPE(STD atomic_intmax_t, STD atomic); CHECK_TYPE(STD atomic_uintmax_t, STD atomic); } - -#if _HAS_CXX20 -static void test_lock_free_types() { - STD atomic_signed_lock_free signed_lf; - CHECK_TYPE(signed_lf.is_lock_free(), true); - volatile STD atomic_signed_lock_free vsigned_lf; - CHECK_TYPE(vsigned_lf.is_lock_free(), true); - STD atomic_unsigned_lock_free unsigned_lf; - CHECK_TYPE(unsigned_lf.is_lock_free(), true); - volatile STD atomic_unsigned_lock_free vunsigned_lf; - CHECK_TYPE(vunsigned_lf.is_lock_free(), true); - static_assert(STD atomic_signed_lock_free::is_always_lock_free); - static_assert(STD atomic_unsigned_lock_free::is_always_lock_free); -} -#endif // _HAS_CXX20 // RUN TESTS void test_main() { // test header test_memory_order_enum(); @@ -875,8 +794,4 @@ void test_main() { // test header test_atomic_udt(); test_fences(); test_typedefs(); -#if _HAS_CXX20 - test_atomic_flag_cxx20(); - test_lock_free_types(); -#endif } From b91269723f7f48ce3e1ed3e59dc4ad4379940ea2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 21:26:57 +0300 Subject: [PATCH 09/15] better test for atomic flags --- tests/std/test.lst | 1 + .../tests/P1135R6_atomic_flag_test/env.lst | 4 + .../tests/P1135R6_atomic_flag_test/test.cpp | 88 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 tests/std/tests/P1135R6_atomic_flag_test/env.lst create mode 100644 tests/std/tests/P1135R6_atomic_flag_test/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index fa0e5e35ce7..4e1896d2b78 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -252,6 +252,7 @@ tests\P0898R3_identity tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink tests\P1023R0_constexpr_for_array_comparisons +tests\P1135R6_atomic_flag_test tests\P1165R1_consistently_propagating_stateful_allocators tests\P1423R3_char8_t_remediation tests\P1645R1_constexpr_numeric diff --git a/tests/std/tests/P1135R6_atomic_flag_test/env.lst b/tests/std/tests/P1135R6_atomic_flag_test/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1135R6_atomic_flag_test/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp new file mode 100644 index 00000000000..8d09c382023 --- /dev/null +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +template +void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear clear) { + constexpr std::size_t unique = 800; + constexpr std::size_t repetitions = 800; + constexpr std::size_t total = unique * repetitions; + constexpr std::size_t dups = total - unique; + + FlagType flags[unique]; + std::vector ptrs; + for (std::size_t i = 0; i != repetitions; i++) { + for (std::size_t j = 0; j != unique; j++) { + ptrs.push_back(&flags[j]); + } + } + + auto pp = std::execution::parallel_policy{}; + + assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); + assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == dups); + assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == total); + assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == total); + std::for_each(pp, ptrs.begin(), ptrs.end(), clear); + assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); +} + +template +void test_flags_members() { + const auto is_set = [](const FlagType* f) { return f->test(); }; + const auto test_and_set = [](FlagType* f) { return f->test_and_set(); }; + const auto clear = [](FlagType* f) { f->clear(); }; + + test_flags(is_set, test_and_set, clear); +} + + +template +void test_flags_members_x() { + constexpr auto mo = std::memory_order_relaxed; + + const auto is_set = [mo](const FlagType* f) { return f->test(mo); }; + const auto test_and_set = [mo](FlagType* f) { return f->test_and_set(mo); }; + const auto clear = [mo](FlagType* f) { f->clear(mo); }; + + test_flags(is_set, test_and_set, clear); +} + +template +void test_flags_free() { + const auto is_set = [](const FlagType* f) { return std::atomic_flag_test(f); }; + const auto test_and_set = [](FlagType* f) { return std::atomic_flag_test_and_set(f); }; + const auto clear = [](FlagType* f) { std::atomic_flag_clear(f); }; + + test_flags(is_set, test_and_set, clear); +} + +template +void test_flags_free_x() { + constexpr auto mo = std::memory_order_relaxed; + + const auto is_set = [mo](const FlagType* f) { return std::atomic_flag_test_explicit(f, mo); }; + const auto test_and_set = [mo](FlagType* f) { return std::atomic_flag_test_and_set_explicit(f, mo); }; + const auto clear = [mo](FlagType* f) { std::atomic_flag_clear_explicit(f, mo); }; + + test_flags(is_set, test_and_set, clear); +} + +template +void test_flag_type() { + test_flags_members(); + test_flags_free(); + test_flags_members_x(); + test_flags_free_x(); +} + +int main() { + test_flag_type(); + test_flag_type(); +} \ No newline at end of file From 1a4e2be0938bffddf8ba6a5a6b41de55d19e08e8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 21:28:48 +0300 Subject: [PATCH 10/15] newline --- tests/std/tests/P1135R6_atomic_flag_test/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp index 8d09c382023..ca0d611cf16 100644 --- a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -85,4 +85,4 @@ void test_flag_type() { int main() { test_flag_type(); test_flag_type(); -} \ No newline at end of file +} From e4691375a6f8bd02d2eafb7506f8b25458dd35ab Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Apr 2020 21:32:42 +0300 Subject: [PATCH 11/15] actually relaxed is wrong --- tests/std/tests/P1135R6_atomic_flag_test/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp index ca0d611cf16..4a16a910a23 100644 --- a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -45,7 +45,7 @@ void test_flags_members() { template void test_flags_members_x() { - constexpr auto mo = std::memory_order_relaxed; + constexpr auto mo = std::memory_order_seq_cst; const auto is_set = [mo](const FlagType* f) { return f->test(mo); }; const auto test_and_set = [mo](FlagType* f) { return f->test_and_set(mo); }; @@ -65,7 +65,7 @@ void test_flags_free() { template void test_flags_free_x() { - constexpr auto mo = std::memory_order_relaxed; + constexpr auto mo = std::memory_order_seq_cst; const auto is_set = [mo](const FlagType* f) { return std::atomic_flag_test_explicit(f, mo); }; const auto test_and_set = [mo](FlagType* f) { return std::atomic_flag_test_and_set_explicit(f, mo); }; From 314a05dd065d1625baf07e87980fb6875ef6ac0e Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 26 Apr 2020 06:14:53 +0300 Subject: [PATCH 12/15] don't capture mo --- .../tests/P1135R6_atomic_flag_test/test.cpp | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp index 4a16a910a23..d3615e3cff9 100644 --- a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -8,6 +8,9 @@ #include #include +constexpr auto mo = std::memory_order_seq_cst; + + template void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear clear) { constexpr std::size_t unique = 800; @@ -23,14 +26,14 @@ void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear c } } - auto pp = std::execution::parallel_policy{}; + const auto& par = std::execution::par; - assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); - assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == dups); - assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == total); - assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == total); - std::for_each(pp, ptrs.begin(), ptrs.end(), clear); - assert(std::transform_reduce(pp, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); + assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); + assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == dups); + assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == total); + assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == total); + std::for_each(par, ptrs.begin(), ptrs.end(), clear); + assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); } template @@ -45,11 +48,9 @@ void test_flags_members() { template void test_flags_members_x() { - constexpr auto mo = std::memory_order_seq_cst; - - const auto is_set = [mo](const FlagType* f) { return f->test(mo); }; - const auto test_and_set = [mo](FlagType* f) { return f->test_and_set(mo); }; - const auto clear = [mo](FlagType* f) { f->clear(mo); }; + const auto is_set = [](const FlagType* f) { return f->test(mo); }; + const auto test_and_set = [](FlagType* f) { return f->test_and_set(mo); }; + const auto clear = [](FlagType* f) { f->clear(mo); }; test_flags(is_set, test_and_set, clear); } @@ -65,11 +66,9 @@ void test_flags_free() { template void test_flags_free_x() { - constexpr auto mo = std::memory_order_seq_cst; - - const auto is_set = [mo](const FlagType* f) { return std::atomic_flag_test_explicit(f, mo); }; - const auto test_and_set = [mo](FlagType* f) { return std::atomic_flag_test_and_set_explicit(f, mo); }; - const auto clear = [mo](FlagType* f) { std::atomic_flag_clear_explicit(f, mo); }; + const auto is_set = [](const FlagType* f) { return std::atomic_flag_test_explicit(f, mo); }; + const auto test_and_set = [](FlagType* f) { return std::atomic_flag_test_and_set_explicit(f, mo); }; + const auto clear = [](FlagType* f) { std::atomic_flag_clear_explicit(f, mo); }; test_flags(is_set, test_and_set, clear); } From 4306cdb05d3b988b978b87785144f3e15335f311 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 7 May 2020 23:09:11 +0300 Subject: [PATCH 13/15] I expect it to pass --- tests/libcxx/expected_results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index fb7bdbc3748..b8358db3d10 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -504,7 +504,7 @@ std/strings/char.traits/char.traits.specializations/char.traits.specializations. std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/move.pass.cpp FAIL # C++20 P1135R6 "The C++20 Synchronization Library" -std/atomics/types.pass.cpp FAIL +std/atomics/types.pass.cpp PASS std/atomics/atomics.types.operations/atomics.types.operations.wait/atomic_wait.pass.cpp FAIL std/thread/thread.barrier/arrive.pass.cpp FAIL std/thread/thread.barrier/arrive_and_drop.pass.cpp FAIL From 66b6275da65ea214a6c4cbacf97a177257a9140b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 May 2020 17:32:47 -0700 Subject: [PATCH 14/15] Code review feedback. --- stl/inc/atomic | 4 ++-- tests/libcxx/expected_results.txt | 1 - tests/libcxx/skipped_tests.txt | 1 - tests/std/tests/P1135R6_atomic_flag_test/test.cpp | 15 ++++++++------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 7a5136b0683..133e7fcd73e 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -2030,11 +2030,11 @@ using atomic_unsigned_lock_free = atomic_uintptr_t; {} struct atomic_flag { // flag with test-and-set semantics #if _HAS_CXX20 - _NODISCARD bool test(const memory_order _Order = memory_order::seq_cst) const noexcept { + _NODISCARD bool test(const memory_order _Order = memory_order_seq_cst) const noexcept { return _Storage.load(_Order) != 0; } - _NODISCARD bool test(const memory_order _Order = memory_order::seq_cst) const volatile noexcept { + _NODISCARD bool test(const memory_order _Order = memory_order_seq_cst) const volatile noexcept { return _Storage.load(_Order) != 0; } #endif // _HAS_CXX20 diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 348f55449a9..f3f01ac71b1 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -504,7 +504,6 @@ std/strings/char.traits/char.traits.specializations/char.traits.specializations. std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/move.pass.cpp FAIL # C++20 P1135R6 "The C++20 Synchronization Library" -std/atomics/types.pass.cpp PASS std/atomics/atomics.types.operations/atomics.types.operations.wait/atomic_wait.pass.cpp FAIL std/thread/thread.barrier/arrive.pass.cpp FAIL std/thread/thread.barrier/arrive_and_drop.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 7fc7f0502aa..8369ae8967c 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -504,7 +504,6 @@ strings\char.traits\char.traits.specializations\char.traits.specializations.wcha strings\char.traits\char.traits.specializations\char.traits.specializations.wchar.t\move.pass.cpp # C++20 P1135R6 "The C++20 Synchronization Library" -atomics\types.pass.cpp atomics\atomics.types.operations\atomics.types.operations.wait\atomic_wait.pass.cpp thread\thread.barrier\arrive.pass.cpp thread\thread.barrier\arrive_and_drop.pass.cpp diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp index d3615e3cff9..51b98e3002b 100644 --- a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -20,13 +21,13 @@ void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear c FlagType flags[unique]; std::vector ptrs; - for (std::size_t i = 0; i != repetitions; i++) { - for (std::size_t j = 0; j != unique; j++) { + for (std::size_t i = 0; i != repetitions; ++i) { + for (std::size_t j = 0; j != unique; ++j) { ptrs.push_back(&flags[j]); } } - const auto& par = std::execution::par; + using std::execution::par; assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, is_set) == 0); assert(std::transform_reduce(par, ptrs.begin(), ptrs.end(), 0, std::plus{}, test_and_set) == dups); @@ -47,7 +48,7 @@ void test_flags_members() { template -void test_flags_members_x() { +void test_flags_members_mo() { const auto is_set = [](const FlagType* f) { return f->test(mo); }; const auto test_and_set = [](FlagType* f) { return f->test_and_set(mo); }; const auto clear = [](FlagType* f) { f->clear(mo); }; @@ -65,7 +66,7 @@ void test_flags_free() { } template -void test_flags_free_x() { +void test_flags_free_mo() { const auto is_set = [](const FlagType* f) { return std::atomic_flag_test_explicit(f, mo); }; const auto test_and_set = [](FlagType* f) { return std::atomic_flag_test_and_set_explicit(f, mo); }; const auto clear = [](FlagType* f) { std::atomic_flag_clear_explicit(f, mo); }; @@ -77,8 +78,8 @@ template void test_flag_type() { test_flags_members(); test_flags_free(); - test_flags_members_x(); - test_flags_free_x(); + test_flags_members_mo(); + test_flags_free_mo(); } int main() { From 949b2590ba0b06fa077ef28b0e296b0a03e0d5e8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 May 2020 18:28:08 -0700 Subject: [PATCH 15/15] Code review feedback, part 2. --- tests/std/tests/P1135R6_atomic_flag_test/test.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp index 51b98e3002b..f82dbed3108 100644 --- a/tests/std/tests/P1135R6_atomic_flag_test/test.cpp +++ b/tests/std/tests/P1135R6_atomic_flag_test/test.cpp @@ -11,7 +11,6 @@ constexpr auto mo = std::memory_order_seq_cst; - template void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear clear) { constexpr std::size_t unique = 800; @@ -21,9 +20,10 @@ void test_flags(const IsSet is_set, const TestAndSet test_and_set, const Clear c FlagType flags[unique]; std::vector ptrs; + ptrs.reserve(total); for (std::size_t i = 0; i != repetitions; ++i) { - for (std::size_t j = 0; j != unique; ++j) { - ptrs.push_back(&flags[j]); + for (auto& flag : flags) { + ptrs.push_back(&flag); } } @@ -46,7 +46,6 @@ void test_flags_members() { test_flags(is_set, test_and_set, clear); } - template void test_flags_members_mo() { const auto is_set = [](const FlagType* f) { return f->test(mo); };