1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// UNSUPPORTED: c++03, c++11, c++14, c++17
9// XFAIL: availability-synchronization_library-missing
10// XFAIL: !has-64-bit-atomics
11
12// void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
13// void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
14
15#include <atomic>
16#include <cassert>
17#include <concepts>
18#include <type_traits>
19#include <vector>
20
21#include "test_helper.h"
22#include "test_macros.h"
23
24#ifndef TEST_HAS_NO_THREADS
25# include "make_test_thread.h"
26# include <thread>
27#endif
28
29template <class T>
30concept HasVolatileWait = requires(volatile std::atomic<T>& a, T t) { a.wait(T()); };
31
32template <class T, template <class> class MaybeVolatile = std::type_identity_t>
33void test_impl() {
34 // Uncomment the test after P1831R1 is implemented
35 // static_assert(HasVolatileWait<T> == std::atomic<T>::is_always_lock_free);
36 static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().wait(T())));
37
38 // wait with different value
39 {
40 MaybeVolatile<std::atomic<T>> a(T(3.1));
41 a.wait(T(1.1), std::memory_order::relaxed);
42 }
43
44#ifndef TEST_HAS_NO_THREADS
45 // equal at the beginning and changed later
46 // bug?? wait can also fail for long double ??
47 // should x87 80bit long double work at all?
48 if constexpr (!std::same_as<T, long double>) {
49 for (auto i = 0; i < 100; ++i) {
50 const T old = T(3.1);
51 MaybeVolatile<std::atomic<T>> a(old);
52
53 std::atomic_bool started = false;
54 bool done = false;
55
56 auto t = support::make_test_thread([&a, &started, old, &done] {
57 started.store(true, std::memory_order::relaxed);
58
59 a.wait(old);
60
61 // likely to fail if wait did not block
62 assert(done);
63 });
64
65 while (!started.load(std::memory_order::relaxed)) {
66 std::this_thread::yield();
67 }
68
69 std::this_thread::sleep_for(rtime: std::chrono::milliseconds(1));
70
71 done = true;
72 a.store(T(9.9));
73 a.notify_all();
74 t.join();
75 }
76 }
77#endif
78
79 // memory_order::acquire
80 {
81 auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
82 auto load = [](MaybeVolatile<std::atomic<T>>& x) {
83 auto result = x.load(std::memory_order::relaxed);
84 x.wait(T(9999.999), std::memory_order::acquire);
85 return result;
86 };
87 test_acquire_release<T, MaybeVolatile>(store, load);
88 }
89
90 // memory_order::seq_cst
91 {
92 auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
93 auto load_no_arg = [](MaybeVolatile<std::atomic<T>>& x) {
94 auto result = x.load(std::memory_order::relaxed);
95 x.wait(T(9999.999));
96 return result;
97 };
98 auto load_with_order = [](MaybeVolatile<std::atomic<T>>& x) {
99 auto result = x.load(std::memory_order::relaxed);
100 x.wait(T(9999.999), std::memory_order::seq_cst);
101 return result;
102 };
103 test_seq_cst<T, MaybeVolatile>(store, load_no_arg);
104 test_seq_cst<T, MaybeVolatile>(store, load_with_order);
105 }
106}
107
108template <class T>
109void test() {
110 test_impl<T>();
111 if constexpr (std::atomic<T>::is_always_lock_free) {
112 test_impl<T, std::add_volatile_t>();
113 }
114}
115
116int main(int, char**) {
117 test<float>();
118 test<double>();
119 // TODO https://github.com/llvm/llvm-project/issues/47978
120 // test<long double>();
121
122 return 0;
123}
124

source code of libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp