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