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//
9// UNSUPPORTED: no-threads
10// UNSUPPORTED: c++03, c++11, c++14, c++17
11// UNSUPPORTED: libcpp-has-no-experimental-stop_token
12// XFAIL: availability-synchronization_library-missing
13
14// <condition_variable>
15
16// class condition_variable_any;
17
18// template<class Lock, class Predicate>
19// bool wait(Lock& lock, stop_token stoken, Predicate pred);
20
21#include <cassert>
22#include <concepts>
23#include <condition_variable>
24#include <functional>
25#include <mutex>
26#include <shared_mutex>
27#include <stop_token>
28#include <thread>
29
30#include "make_test_thread.h"
31#include "test_macros.h"
32
33template <class Mutex, class Lock>
34void test() {
35 // stop_requested before hand
36 {
37 std::stop_source ss;
38 std::condition_variable_any cv;
39 Mutex mutex;
40 Lock lock{mutex};
41 ss.request_stop();
42
43 // [Note 1: The returned value indicates whether the predicate evaluated to true regardless of whether there was a stop request.]
44 std::same_as<bool> auto r1 = cv.wait(lock, ss.get_token(), []() { return false; });
45 assert(!r1);
46
47 std::same_as<bool> auto r2 = cv.wait(lock, ss.get_token(), []() { return true; });
48 assert(r2);
49
50 // Postconditions: lock is locked by the calling thread.
51 assert(lock.owns_lock());
52 }
53
54 // no stop request
55 {
56 std::stop_source ss;
57 std::condition_variable_any cv;
58 Mutex mutex;
59 Lock lock{mutex};
60 std::same_as<bool> auto r1 = cv.wait(lock, ss.get_token(), []() { return true; });
61 assert(r1);
62
63 bool flag = false;
64 auto thread = support::make_test_thread([&]() {
65 std::this_thread::sleep_for(std::chrono::milliseconds(2));
66 std::unique_lock<Mutex> lock2{mutex};
67 flag = true;
68 cv.notify_all();
69 });
70
71 std::same_as<bool> auto r2 = cv.wait(lock, ss.get_token(), [&]() { return flag; });
72 assert(flag);
73 assert(r2);
74 thread.join();
75
76 assert(lock.owns_lock());
77 }
78
79 // stop request comes while waiting
80 {
81 std::stop_source ss;
82 std::condition_variable_any cv;
83 Mutex mutex;
84 Lock lock{mutex};
85
86 std::atomic_bool start = false;
87 std::atomic_bool done = false;
88 auto thread = support::make_test_thread([&]() {
89 start.wait(false);
90 ss.request_stop();
91
92 while (!done) {
93 cv.notify_all();
94 std::this_thread::sleep_for(std::chrono::milliseconds(2));
95 }
96 });
97
98 std::same_as<bool> auto r = cv.wait(lock, ss.get_token(), [&]() {
99 start.store(true);
100 start.notify_all();
101 return false;
102 });
103 assert(!r);
104 done = true;
105 thread.join();
106
107 assert(lock.owns_lock());
108 }
109
110 // #76807 Hangs in std::condition_variable_any when used with std::stop_token
111 {
112 class MyThread {
113 public:
114 MyThread() {
115 thread_ = support::make_test_jthread([this](std::stop_token st) {
116 while (!st.stop_requested()) {
117 std::unique_lock lock{m_};
118 cv_.wait(lock, st, [] { return false; });
119 }
120 });
121 }
122
123 private:
124 std::mutex m_;
125 std::condition_variable_any cv_;
126 std::jthread thread_;
127 };
128
129 [[maybe_unused]] MyThread my_thread;
130 }
131
132 // request_stop potentially in-between check and wait
133 {
134 std::stop_source ss;
135 std::condition_variable_any cv;
136 Mutex mutex;
137 Lock lock{mutex};
138
139 std::atomic_bool pred_started = false;
140 std::atomic_bool request_stop_called = false;
141 auto thread = support::make_test_thread([&]() {
142 pred_started.wait(false);
143 ss.request_stop();
144 request_stop_called.store(true);
145 request_stop_called.notify_all();
146 });
147
148 std::same_as<bool> auto r = cv.wait(lock, ss.get_token(), [&]() {
149 pred_started.store(true);
150 pred_started.notify_all();
151 request_stop_called.wait(false);
152 return false;
153 });
154 assert(!r);
155 thread.join();
156
157 assert(lock.owns_lock());
158 }
159
160#if !defined(TEST_HAS_NO_EXCEPTIONS)
161 // Throws: Any exception thrown by pred.
162 {
163 std::stop_source ss;
164 std::condition_variable_any cv;
165 Mutex mutex;
166 Lock lock{mutex};
167
168 try {
169 cv.wait(lock, ss.get_token(), []() -> bool { throw 5; });
170 assert(false);
171 } catch (int i) {
172 assert(i == 5);
173 }
174 }
175#endif //!defined(TEST_HAS_NO_EXCEPTIONS)
176}
177
178int main(int, char**) {
179 test<std::mutex, std::unique_lock<std::mutex>>();
180 test<std::shared_mutex, std::shared_lock<std::shared_mutex>>();
181
182 return 0;
183}
184

source code of libcxx/test/std/thread/thread.condition/thread.condition.condvarany/wait_token_pred.pass.cpp