14fa812bbSHui //===----------------------------------------------------------------------===// 24fa812bbSHui // 34fa812bbSHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44fa812bbSHui // See https://llvm.org/LICENSE.txt for license information. 54fa812bbSHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64fa812bbSHui // 74fa812bbSHui //===----------------------------------------------------------------------===// 84fa812bbSHui // 94fa812bbSHui // UNSUPPORTED: no-threads 104fa812bbSHui // UNSUPPORTED: c++03, c++11, c++14, c++17 114fa812bbSHui // XFAIL: availability-synchronization_library-missing 124fa812bbSHui 134fa812bbSHui // <condition_variable> 144fa812bbSHui 154fa812bbSHui // class condition_variable_any; 164fa812bbSHui 174fa812bbSHui // template<class Lock, class Predicate> 184fa812bbSHui // bool wait(Lock& lock, stop_token stoken, Predicate pred); 194fa812bbSHui 20*09e3a360SLouis Dionne #include <atomic> 214fa812bbSHui #include <cassert> 224fa812bbSHui #include <concepts> 234fa812bbSHui #include <condition_variable> 244fa812bbSHui #include <functional> 254fa812bbSHui #include <mutex> 264fa812bbSHui #include <shared_mutex> 274fa812bbSHui #include <stop_token> 284fa812bbSHui #include <thread> 294fa812bbSHui 304fa812bbSHui #include "make_test_thread.h" 314fa812bbSHui #include "test_macros.h" 324fa812bbSHui 334fa812bbSHui template <class Mutex, class Lock> 344fa812bbSHui void test() { 354fa812bbSHui // stop_requested before hand 364fa812bbSHui { 374fa812bbSHui std::stop_source ss; 384fa812bbSHui std::condition_variable_any cv; 394fa812bbSHui Mutex mutex; 404fa812bbSHui Lock lock{mutex}; 414fa812bbSHui ss.request_stop(); 424fa812bbSHui 434fa812bbSHui // [Note 1: The returned value indicates whether the predicate evaluated to true regardless of whether there was a stop request.] 444fa812bbSHui std::same_as<bool> auto r1 = cv.wait(lock, ss.get_token(), []() { return false; }); 454fa812bbSHui assert(!r1); 464fa812bbSHui 474fa812bbSHui std::same_as<bool> auto r2 = cv.wait(lock, ss.get_token(), []() { return true; }); 484fa812bbSHui assert(r2); 494fa812bbSHui 504fa812bbSHui // Postconditions: lock is locked by the calling thread. 514fa812bbSHui assert(lock.owns_lock()); 524fa812bbSHui } 534fa812bbSHui 544fa812bbSHui // no stop request 554fa812bbSHui { 564fa812bbSHui std::stop_source ss; 574fa812bbSHui std::condition_variable_any cv; 584fa812bbSHui Mutex mutex; 594fa812bbSHui Lock lock{mutex}; 604fa812bbSHui std::same_as<bool> auto r1 = cv.wait(lock, ss.get_token(), []() { return true; }); 614fa812bbSHui assert(r1); 624fa812bbSHui 634fa812bbSHui bool flag = false; 644fa812bbSHui auto thread = support::make_test_thread([&]() { 654fa812bbSHui std::this_thread::sleep_for(std::chrono::milliseconds(2)); 6681e2693cSHui std::unique_lock<Mutex> lock2{mutex}; 674fa812bbSHui flag = true; 684fa812bbSHui cv.notify_all(); 694fa812bbSHui }); 704fa812bbSHui 714fa812bbSHui std::same_as<bool> auto r2 = cv.wait(lock, ss.get_token(), [&]() { return flag; }); 724fa812bbSHui assert(flag); 734fa812bbSHui assert(r2); 744fa812bbSHui thread.join(); 754fa812bbSHui 764fa812bbSHui assert(lock.owns_lock()); 774fa812bbSHui } 784fa812bbSHui 794fa812bbSHui // stop request comes while waiting 804fa812bbSHui { 814fa812bbSHui std::stop_source ss; 824fa812bbSHui std::condition_variable_any cv; 834fa812bbSHui Mutex mutex; 844fa812bbSHui Lock lock{mutex}; 854fa812bbSHui 864fa812bbSHui std::atomic_bool start = false; 874fa812bbSHui std::atomic_bool done = false; 884fa812bbSHui auto thread = support::make_test_thread([&]() { 894fa812bbSHui start.wait(false); 904fa812bbSHui ss.request_stop(); 914fa812bbSHui 924fa812bbSHui while (!done) { 934fa812bbSHui cv.notify_all(); 944fa812bbSHui std::this_thread::sleep_for(std::chrono::milliseconds(2)); 954fa812bbSHui } 964fa812bbSHui }); 974fa812bbSHui 984fa812bbSHui std::same_as<bool> auto r = cv.wait(lock, ss.get_token(), [&]() { 994fa812bbSHui start.store(true); 1004fa812bbSHui start.notify_all(); 1014fa812bbSHui return false; 1024fa812bbSHui }); 1034fa812bbSHui assert(!r); 1044fa812bbSHui done = true; 1054fa812bbSHui thread.join(); 1064fa812bbSHui 1074fa812bbSHui assert(lock.owns_lock()); 1084fa812bbSHui } 1094fa812bbSHui 11085a8e5c3SHui // #76807 Hangs in std::condition_variable_any when used with std::stop_token 11185a8e5c3SHui { 11285a8e5c3SHui class MyThread { 11385a8e5c3SHui public: 11485a8e5c3SHui MyThread() { 11585a8e5c3SHui thread_ = support::make_test_jthread([this](std::stop_token st) { 11685a8e5c3SHui while (!st.stop_requested()) { 11785a8e5c3SHui std::unique_lock lock{m_}; 11885a8e5c3SHui cv_.wait(lock, st, [] { return false; }); 11985a8e5c3SHui } 12085a8e5c3SHui }); 12185a8e5c3SHui } 12285a8e5c3SHui 12385a8e5c3SHui private: 12485a8e5c3SHui std::mutex m_; 12585a8e5c3SHui std::condition_variable_any cv_; 12685a8e5c3SHui std::jthread thread_; 12785a8e5c3SHui }; 12885a8e5c3SHui 12985a8e5c3SHui [[maybe_unused]] MyThread my_thread; 13085a8e5c3SHui } 13185a8e5c3SHui 13285a8e5c3SHui // request_stop potentially in-between check and wait 13385a8e5c3SHui { 13485a8e5c3SHui std::stop_source ss; 13585a8e5c3SHui std::condition_variable_any cv; 13685a8e5c3SHui Mutex mutex; 13785a8e5c3SHui Lock lock{mutex}; 13885a8e5c3SHui 13985a8e5c3SHui std::atomic_bool pred_started = false; 14085a8e5c3SHui std::atomic_bool request_stop_called = false; 14185a8e5c3SHui auto thread = support::make_test_thread([&]() { 14285a8e5c3SHui pred_started.wait(false); 14385a8e5c3SHui ss.request_stop(); 14485a8e5c3SHui request_stop_called.store(true); 14585a8e5c3SHui request_stop_called.notify_all(); 14685a8e5c3SHui }); 14785a8e5c3SHui 14885a8e5c3SHui std::same_as<bool> auto r = cv.wait(lock, ss.get_token(), [&]() { 14985a8e5c3SHui pred_started.store(true); 15085a8e5c3SHui pred_started.notify_all(); 15185a8e5c3SHui request_stop_called.wait(false); 15285a8e5c3SHui return false; 15385a8e5c3SHui }); 15485a8e5c3SHui assert(!r); 15585a8e5c3SHui thread.join(); 15685a8e5c3SHui 15785a8e5c3SHui assert(lock.owns_lock()); 15885a8e5c3SHui } 15985a8e5c3SHui 1604fa812bbSHui #if !defined(TEST_HAS_NO_EXCEPTIONS) 1614fa812bbSHui // Throws: Any exception thrown by pred. 1624fa812bbSHui { 1634fa812bbSHui std::stop_source ss; 1644fa812bbSHui std::condition_variable_any cv; 1654fa812bbSHui Mutex mutex; 1664fa812bbSHui Lock lock{mutex}; 1674fa812bbSHui 1684fa812bbSHui try { 1694fa812bbSHui cv.wait(lock, ss.get_token(), []() -> bool { throw 5; }); 1704fa812bbSHui assert(false); 1714fa812bbSHui } catch (int i) { 1724fa812bbSHui assert(i == 5); 1734fa812bbSHui } 1744fa812bbSHui } 1754fa812bbSHui #endif //!defined(TEST_HAS_NO_EXCEPTIONS) 1764fa812bbSHui } 1774fa812bbSHui 1784fa812bbSHui int main(int, char**) { 1794fa812bbSHui test<std::mutex, std::unique_lock<std::mutex>>(); 1804fa812bbSHui test<std::shared_mutex, std::shared_lock<std::shared_mutex>>(); 1814fa812bbSHui 1824fa812bbSHui return 0; 1834fa812bbSHui } 184