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 // [[nodiscard]] bool stop_requested() const noexcept; 14 // Returns: true if *this has ownership of a stop state that has received a stop request; otherwise, false. 15 16 #include <cassert> 17 #include <chrono> 18 #include <concepts> 19 #include <optional> 20 #include <stop_token> 21 #include <type_traits> 22 23 #include "make_test_thread.h" 24 #include "test_macros.h" 25 26 template <class T> 27 concept IsStopRequestedNoexcept = requires(const T& t) { 28 { t.stop_requested() } noexcept; 29 }; 30 31 static_assert(IsStopRequestedNoexcept<std::stop_token>); 32 33 int main(int, char**) { 34 // no state 35 { 36 const std::stop_token st; 37 assert(!st.stop_requested()); 38 } 39 40 // has state 41 { 42 std::stop_source ss; 43 const auto st = ss.get_token(); 44 assert(!st.stop_requested()); 45 46 ss.request_stop(); 47 assert(st.stop_requested()); 48 } 49 50 // already requested before constructor 51 { 52 std::stop_source ss; 53 ss.request_stop(); 54 const auto st = ss.get_token(); 55 assert(st.stop_requested()); 56 } 57 58 // stop_token should share the state 59 { 60 std::optional<std::stop_source> ss{std::in_place}; 61 ss->request_stop(); 62 const auto st = ss->get_token(); 63 64 ss.reset(); 65 assert(st.stop_requested()); 66 } 67 68 // single stop_source, multiple stop_token 69 { 70 std::stop_source ss; 71 const auto st1 = ss.get_token(); 72 const auto st2 = ss.get_token(); 73 assert(!st1.stop_requested()); 74 assert(!st2.stop_requested()); 75 76 ss.request_stop(); 77 assert(st1.stop_requested()); 78 assert(st2.stop_requested()); 79 } 80 81 // multiple stop_source, multiple stop_token 82 { 83 std::stop_source ss1; 84 std::stop_source ss2; 85 86 const auto st1 = ss1.get_token(); 87 const auto st2 = ss2.get_token(); 88 assert(!st1.stop_requested()); 89 assert(!st2.stop_requested()); 90 91 ss1.request_stop(); 92 assert(st1.stop_requested()); 93 assert(!st2.stop_requested()); 94 } 95 96 // multiple threads 97 { 98 std::stop_source ss; 99 const auto st = ss.get_token(); 100 assert(!st.stop_requested()); 101 102 std::thread t = support::make_test_thread([&]() { ss.request_stop(); }); 103 104 t.join(); 105 assert(st.stop_requested()); 106 } 107 108 // maybe concurrent calls 109 { 110 std::stop_source ss; 111 const auto st = ss.get_token(); 112 assert(!st.stop_requested()); 113 114 std::thread t = support::make_test_thread([&]() { ss.request_stop(); }); 115 116 while (!st.stop_requested()) { 117 // should eventually exit the loop 118 std::this_thread::yield(); 119 } 120 121 t.join(); 122 } 123 124 // [thread.stoptoken.intro] A call to request_stop that returns true 125 // synchronizes with a call to stop_requested on an associated stop_token 126 // or stop_source object that returns true. 127 { 128 std::stop_source ss; 129 const auto st = ss.get_token(); 130 assert(!st.stop_requested()); 131 132 bool flag = false; 133 134 std::thread t = support::make_test_thread([&]() { 135 using namespace std::chrono_literals; 136 std::this_thread::sleep_for(1ms); 137 138 // happens-before request_stop 139 flag = true; 140 auto b = ss.request_stop(); 141 assert(b); 142 }); 143 144 while (!st.stop_requested()) { 145 std::this_thread::yield(); 146 } 147 148 // write should be visible to the current thread 149 assert(flag == true); 150 151 t.join(); 152 } 153 154 return 0; 155 } 156