[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / libcxx / test / std / thread / thread.stoptoken / stopcallback / cons.rvalue.token.pass.cpp
blobf78643def5ce37ce7836f97d7b9dedc8738f332f
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: libcpp-has-no-experimental-stop_token
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
12 // XFAIL: availability-synchronization_library-missing
14 // template<class C>
15 // explicit stop_callback(stop_token&& st, C&& cb)
16 // noexcept(is_nothrow_constructible_v<Callback, C>);
18 #include <atomic>
19 #include <cassert>
20 #include <chrono>
21 #include <stop_token>
22 #include <type_traits>
23 #include <utility>
24 #include <vector>
26 #include "make_test_thread.h"
27 #include "test_macros.h"
29 struct Cb {
30 void operator()() const;
33 // Constraints: Callback and C satisfy constructible_from<Callback, C>.
34 static_assert(std::is_constructible_v<std::stop_callback<void (*)()>, std::stop_token&&, void (*)()>);
35 static_assert(!std::is_constructible_v<std::stop_callback<void (*)()>, std::stop_token&&, void (*)(int)>);
36 static_assert(std::is_constructible_v<std::stop_callback<Cb>, std::stop_token&&, Cb&>);
37 static_assert(std::is_constructible_v<std::stop_callback<Cb&>, std::stop_token&&, Cb&>);
38 static_assert(!std::is_constructible_v<std::stop_callback<Cb>, std::stop_token&&, int>);
40 // explicit
41 template <class T>
42 void conversion_test(T);
44 template <class T, class... Args>
45 concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
46 static_assert(ImplicitlyConstructible<int, int>);
47 static_assert(!ImplicitlyConstructible<std::stop_callback<Cb>, std::stop_token&&, Cb>);
49 // noexcept
50 template <bool NoExceptCtor>
51 struct CbNoExcept {
52 CbNoExcept(int) noexcept(NoExceptCtor);
53 void operator()() const;
55 static_assert(std::is_nothrow_constructible_v<std::stop_callback<CbNoExcept<true>>, std::stop_token&&, int>);
56 static_assert(!std::is_nothrow_constructible_v<std::stop_callback<CbNoExcept<false>>, std::stop_token&&, int>);
58 int main(int, char**) {
59 // was requested
61 std::stop_source ss;
62 ss.request_stop();
64 bool called = false;
65 std::stop_callback sc(ss.get_token(), [&] { called = true; });
66 assert(called);
69 // was not requested
71 std::stop_source ss;
73 bool called = false;
74 std::stop_callback sc(ss.get_token(), [&] { called = true; });
75 assert(!called);
77 ss.request_stop();
78 assert(called);
81 // token has no state
83 std::stop_token st;
84 bool called = false;
85 std::stop_callback sc(std::move(st), [&] { called = true; });
86 assert(!called);
89 // should not be called multiple times
91 std::stop_source ss;
93 int calledTimes = 0;
94 std::stop_callback sc(ss.get_token(), [&] { ++calledTimes; });
96 std::vector<std::thread> threads;
97 for (auto i = 0; i < 10; ++i) {
98 threads.emplace_back(support::make_test_thread([&] { ss.request_stop(); }));
101 for (auto& thread : threads) {
102 thread.join();
104 assert(calledTimes == 1);
107 // adding more callbacks during invoking other callbacks
109 std::stop_source ss;
111 std::atomic<bool> startedFlag = false;
112 std::atomic<bool> finishFlag = false;
113 std::stop_callback sc(ss.get_token(), [&] {
114 startedFlag = true;
115 startedFlag.notify_all();
116 finishFlag.wait(false);
119 auto thread = support::make_test_thread([&] { ss.request_stop(); });
121 startedFlag.wait(false);
123 // first callback is still running, adding another one;
124 bool secondCallbackCalled = false;
125 std::stop_callback sc2(ss.get_token(), [&] { secondCallbackCalled = true; });
127 finishFlag = true;
128 finishFlag.notify_all();
130 thread.join();
131 assert(secondCallbackCalled);
134 // adding callbacks on different threads
136 std::stop_source ss;
138 std::vector<std::thread> threads;
139 std::atomic<int> callbackCalledTimes = 0;
140 std::atomic<bool> done = false;
141 for (auto i = 0; i < 10; ++i) {
142 threads.emplace_back(support::make_test_thread([&] {
143 std::stop_callback sc{ss.get_token(), [&] { callbackCalledTimes.fetch_add(1, std::memory_order_relaxed); }};
144 done.wait(false);
145 }));
147 using namespace std::chrono_literals;
148 std::this_thread::sleep_for(1ms);
149 ss.request_stop();
150 done = true;
151 done.notify_all();
152 for (auto& thread : threads) {
153 thread.join();
155 assert(callbackCalledTimes.load(std::memory_order_relaxed) == 10);
158 // correct overload
160 struct CBWithTracking {
161 bool& lvalueCalled;
162 bool& lvalueConstCalled;
163 bool& rvalueCalled;
164 bool& rvalueConstCalled;
166 void operator()() & { lvalueCalled = true; }
167 void operator()() const& { lvalueConstCalled = true; }
168 void operator()() && { rvalueCalled = true; }
169 void operator()() const&& { rvalueConstCalled = true; }
172 // RValue
174 bool lvalueCalled = false;
175 bool lvalueConstCalled = false;
176 bool rvalueCalled = false;
177 bool rvalueConstCalled = false;
178 std::stop_source ss;
179 ss.request_stop();
181 std::stop_callback<CBWithTracking> sc(
182 ss.get_token(), CBWithTracking{lvalueCalled, lvalueConstCalled, rvalueCalled, rvalueConstCalled});
183 assert(rvalueCalled);
186 // RValue
188 bool lvalueCalled = false;
189 bool lvalueConstCalled = false;
190 bool rvalueCalled = false;
191 bool rvalueConstCalled = false;
192 std::stop_source ss;
193 ss.request_stop();
195 std::stop_callback<const CBWithTracking> sc(
196 ss.get_token(), CBWithTracking{lvalueCalled, lvalueConstCalled, rvalueCalled, rvalueConstCalled});
197 assert(rvalueConstCalled);
200 // LValue
202 bool lvalueCalled = false;
203 bool lvalueConstCalled = false;
204 bool rvalueCalled = false;
205 bool rvalueConstCalled = false;
206 std::stop_source ss;
207 ss.request_stop();
208 CBWithTracking cb{lvalueCalled, lvalueConstCalled, rvalueCalled, rvalueConstCalled};
209 std::stop_callback<CBWithTracking&> sc(ss.get_token(), cb);
210 assert(lvalueCalled);
213 // const LValue
215 bool lvalueCalled = false;
216 bool lvalueConstCalled = false;
217 bool rvalueCalled = false;
218 bool rvalueConstCalled = false;
219 std::stop_source ss;
220 ss.request_stop();
221 CBWithTracking cb{lvalueCalled, lvalueConstCalled, rvalueCalled, rvalueConstCalled};
222 std::stop_callback<const CBWithTracking&> sc(ss.get_token(), cb);
223 assert(lvalueConstCalled);
227 return 0;