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