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 // XFAIL: availability-synchronization_library-missing 12 13 // <condition_variable> 14 15 // class condition_variable_any; 16 17 // template<class Lock, class Predicate> 18 // bool wait(Lock& lock, stop_token stoken, Predicate pred); 19 20 #include <atomic> 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 33 template <class Mutex, class Lock> 34 void 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 178 int 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