1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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
15 // explicit stop_callback(stop_token&& st, C&& cb)
16 // noexcept(is_nothrow_constructible_v<Callback, C>);
22 #include <type_traits>
26 #include "make_test_thread.h"
27 #include "test_macros.h"
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>);
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
>);
50 template <bool NoExceptCtor
>
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**) {
65 std::stop_callback
sc(ss
.get_token(), [&] { called
= true; });
74 std::stop_callback
sc(ss
.get_token(), [&] { called
= true; });
85 std::stop_callback
sc(std::move(st
), [&] { called
= true; });
89 // should not be called multiple times
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
) {
104 assert(calledTimes
== 1);
107 // adding more callbacks during invoking other callbacks
111 std::atomic
<bool> startedFlag
= false;
112 std::atomic
<bool> finishFlag
= false;
113 std::stop_callback
sc(ss
.get_token(), [&] {
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; });
128 finishFlag
.notify_all();
131 assert(secondCallbackCalled
);
134 // adding callbacks on different threads
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
); }};
147 using namespace std::chrono_literals
;
148 std::this_thread::sleep_for(1ms
);
152 for (auto& thread
: threads
) {
155 assert(callbackCalledTimes
.load(std::memory_order_relaxed
) == 10);
160 struct CBWithTracking
{
162 bool& lvalueConstCalled
;
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; }
174 bool lvalueCalled
= false;
175 bool lvalueConstCalled
= false;
176 bool rvalueCalled
= false;
177 bool rvalueConstCalled
= false;
181 std::stop_callback
<CBWithTracking
> sc(
182 ss
.get_token(), CBWithTracking
{lvalueCalled
, lvalueConstCalled
, rvalueCalled
, rvalueConstCalled
});
183 assert(rvalueCalled
);
188 bool lvalueCalled
= false;
189 bool lvalueConstCalled
= false;
190 bool rvalueCalled
= false;
191 bool rvalueConstCalled
= false;
195 std::stop_callback
<const CBWithTracking
> sc(
196 ss
.get_token(), CBWithTracking
{lvalueCalled
, lvalueConstCalled
, rvalueCalled
, rvalueConstCalled
});
197 assert(rvalueConstCalled
);
202 bool lvalueCalled
= false;
203 bool lvalueConstCalled
= false;
204 bool rvalueCalled
= false;
205 bool rvalueConstCalled
= false;
208 CBWithTracking cb
{lvalueCalled
, lvalueConstCalled
, rvalueCalled
, rvalueConstCalled
};
209 std::stop_callback
<CBWithTracking
&> sc(ss
.get_token(), cb
);
210 assert(lvalueCalled
);
215 bool lvalueCalled
= false;
216 bool lvalueConstCalled
= false;
217 bool rvalueCalled
= false;
218 bool rvalueConstCalled
= false;
221 CBWithTracking cb
{lvalueCalled
, lvalueConstCalled
, rvalueCalled
, rvalueConstCalled
};
222 std::stop_callback
<const CBWithTracking
&> sc(ss
.get_token(), cb
);
223 assert(lvalueConstCalled
);