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

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