xref: /llvm-project/libcxx/test/std/thread/thread.stoptoken/stoptoken/stop_requested.pass.cpp (revision 121ed5c1985356436d0040dbe81bca26992b1fae)
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