-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Introduce make_test_jthread for jthread tests #68837
Conversation
@llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne) ChangesThis patch introduces the support::make_test_jthread utility which is basically the same as support::make_test_thread but for std::jthread. It allows vendors to maintain a downstream way to create threads for use within the test suite, which is especially useful for embedded platforms. Full diff: https://github.com/llvm/llvm-project/pull/68837.diff 14 Files Affected:
diff --git a/libcxx/test/std/thread/thread.jthread/assign.move.pass.cpp b/libcxx/test/std/thread/thread.jthread/assign.move.pass.cpp
index b932ac39d2f3773..89521ad7660a120 100644
--- a/libcxx/test/std/thread/thread.jthread/assign.move.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/assign.move.pass.cpp
@@ -23,6 +23,7 @@
#include <utility>
#include <vector>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(std::is_nothrow_move_assignable_v<std::jthread>);
@@ -30,10 +31,10 @@ static_assert(std::is_nothrow_move_assignable_v<std::jthread>);
int main(int, char**) {
// If &x == this is true, there are no effects.
{
- std::jthread j([] {});
- auto id = j.get_id();
- auto ssource = j.get_stop_source();
- j = std::move(j);
+ std::jthread j = support::make_test_jthread([] {});
+ auto id = j.get_id();
+ auto ssource = j.get_stop_source();
+ j = std::move(j);
assert(j.get_id() == id);
assert(j.get_stop_source() == ssource);
}
@@ -41,12 +42,12 @@ int main(int, char**) {
// if joinable() is true, calls request_stop() and then join()
// request_stop is called
{
- std::jthread j1([] {});
- bool called = false;
+ std::jthread j1 = support::make_test_jthread([] {});
+ bool called = false;
std::stop_callback cb(j1.get_stop_token(), [&called] { called = true; });
- std::jthread j2([] {});
- j1 = std::move(j2);
+ std::jthread j2 = support::make_test_jthread([] {});
+ j1 = std::move(j2);
assert(called);
}
@@ -58,10 +59,10 @@ int main(int, char**) {
constexpr auto numberOfThreads = 10u;
jts.reserve(numberOfThreads);
for (auto i = 0u; i < numberOfThreads; ++i) {
- jts.emplace_back([&] {
+ jts.emplace_back(support::make_test_jthread([&] {
std::this_thread::sleep_for(std::chrono::milliseconds(2));
calledTimes.fetch_add(1, std::memory_order_relaxed);
- });
+ }));
}
for (auto i = 0u; i < numberOfThreads; ++i) {
@@ -79,10 +80,10 @@ int main(int, char**) {
// then assigns the state of x to *this
{
- std::jthread j1([] {});
- std::jthread j2([] {});
- auto id2 = j2.get_id();
- auto ssource2 = j2.get_stop_source();
+ std::jthread j1 = support::make_test_jthread([] {});
+ std::jthread j2 = support::make_test_jthread([] {});
+ auto id2 = j2.get_id();
+ auto ssource2 = j2.get_stop_source();
j1 = std::move(j2);
@@ -92,9 +93,9 @@ int main(int, char**) {
// sets x to a default constructed state
{
- std::jthread j1([] {});
- std::jthread j2([] {});
- j1 = std::move(j2);
+ std::jthread j1 = support::make_test_jthread([] {});
+ std::jthread j2 = support::make_test_jthread([] {});
+ j1 = std::move(j2);
assert(j2.get_id() == std::jthread::id());
assert(!j2.get_stop_source().stop_possible());
@@ -103,7 +104,7 @@ int main(int, char**) {
// joinable is false
{
std::jthread j1;
- std::jthread j2([] {});
+ std::jthread j2 = support::make_test_jthread([] {});
auto j2Id = j2.get_id();
diff --git a/libcxx/test/std/thread/thread.jthread/cons.move.pass.cpp b/libcxx/test/std/thread/thread.jthread/cons.move.pass.cpp
index 9eacf8971c2a58b..c3c04467703c96e 100644
--- a/libcxx/test/std/thread/thread.jthread/cons.move.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/cons.move.pass.cpp
@@ -19,6 +19,7 @@
#include <type_traits>
#include <utility>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(std::is_nothrow_move_constructible_v<std::jthread>);
@@ -27,8 +28,8 @@ int main(int, char**) {
{
// x.get_id() == id() and get_id() returns the value of x.get_id() prior
// to the start of construction.
- std::jthread j1{[] {}};
- auto id1 = j1.get_id();
+ std::jthread j1 = support::make_test_jthread([] {});
+ auto id1 = j1.get_id();
std::jthread j2(std::move(j1));
assert(j1.get_id() == std::jthread::id());
@@ -38,8 +39,8 @@ int main(int, char**) {
{
// ssource has the value of x.ssource prior to the start of construction
// and x.ssource.stop_possible() is false.
- std::jthread j1{[] {}};
- auto ss1 = j1.get_stop_source();
+ std::jthread j1 = support::make_test_jthread([] {});
+ auto ss1 = j1.get_stop_source();
std::jthread j2(std::move(j1));
assert(ss1 == j2.get_stop_source());
diff --git a/libcxx/test/std/thread/thread.jthread/detach.pass.cpp b/libcxx/test/std/thread/thread.jthread/detach.pass.cpp
index ee48d2691e68439..54fd5fd93bed6f3 100644
--- a/libcxx/test/std/thread/thread.jthread/detach.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/detach.pass.cpp
@@ -23,6 +23,7 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
int main(int, char**) {
@@ -30,10 +31,10 @@ int main(int, char**) {
{
std::atomic_bool start{false};
std::atomic_bool done{false};
- std::optional<std::jthread> jt{[&start, &done] {
+ std::optional<std::jthread> jt = support::make_test_jthread([&start, &done] {
start.wait(false);
done = true;
- }};
+ });
// If it blocks, it will deadlock here
jt->detach();
@@ -49,7 +50,7 @@ int main(int, char**) {
// Postconditions: get_id() == id().
{
- std::jthread jt{[] {}};
+ std::jthread jt = support::make_test_jthread([] {});
assert(jt.get_id() != std::jthread::id());
jt.detach();
assert(jt.get_id() == std::jthread::id());
diff --git a/libcxx/test/std/thread/thread.jthread/dtor.pass.cpp b/libcxx/test/std/thread/thread.jthread/dtor.pass.cpp
index 47ee62023f62d94..35be0f6c0dd82c8 100644
--- a/libcxx/test/std/thread/thread.jthread/dtor.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/dtor.pass.cpp
@@ -20,6 +20,8 @@
#include <thread>
#include <type_traits>
#include <vector>
+
+#include "make_test_thread.h"
#include "test_macros.h"
int main(int, char**) {
@@ -32,8 +34,8 @@ int main(int, char**) {
// If joinable() is true, calls request_stop() and then join().
// request_stop is called
{
- std::optional<std::jthread> jt([] {});
- bool called = false;
+ std::optional<std::jthread> jt = support::make_test_jthread([] {});
+ bool called = false;
std::stop_callback cb(jt->get_stop_token(), [&called] { called = true; });
jt.reset();
assert(called);
@@ -48,10 +50,10 @@ int main(int, char**) {
constexpr auto numberOfThreads = 10u;
jts.reserve(numberOfThreads);
for (auto i = 0u; i < numberOfThreads; ++i) {
- jts.emplace_back([&calledTimes] {
+ jts.emplace_back(support::make_test_jthread([&calledTimes] {
std::this_thread::sleep_for(std::chrono::milliseconds{2});
calledTimes.fetch_add(1, std::memory_order_relaxed);
- });
+ }));
}
jts.clear();
diff --git a/libcxx/test/std/thread/thread.jthread/get_id.pass.cpp b/libcxx/test/std/thread/thread.jthread/get_id.pass.cpp
index f92472d3d8dc649..b3a2beff9f416af 100644
--- a/libcxx/test/std/thread/thread.jthread/get_id.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/get_id.pass.cpp
@@ -18,6 +18,7 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(noexcept(std::declval<const std::jthread&>().get_id()));
@@ -32,7 +33,7 @@ int main(int, char**) {
// Represents a thread
{
- const std::jthread jt{[] {}};
+ const std::jthread jt = support::make_test_jthread([] {});
std::same_as<std::jthread::id> decltype(auto) result = jt.get_id();
assert(result != std::jthread::id());
}
diff --git a/libcxx/test/std/thread/thread.jthread/get_stop_source.pass.cpp b/libcxx/test/std/thread/thread.jthread/get_stop_source.pass.cpp
index 41df2d894f45df0..8f35db297b74962 100644
--- a/libcxx/test/std/thread/thread.jthread/get_stop_source.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/get_stop_source.pass.cpp
@@ -19,6 +19,7 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(noexcept(std::declval<std::jthread&>().get_stop_source()));
@@ -26,7 +27,7 @@ static_assert(noexcept(std::declval<std::jthread&>().get_stop_source()));
int main(int, char**) {
// Represents a thread
{
- std::jthread jt{[] {}};
+ std::jthread jt = support::make_test_jthread([] {});
std::same_as<std::stop_source> decltype(auto) result = jt.get_stop_source();
assert(result.stop_possible());
}
diff --git a/libcxx/test/std/thread/thread.jthread/get_stop_token.pass.cpp b/libcxx/test/std/thread/thread.jthread/get_stop_token.pass.cpp
index c65d39b3cdf4a77..070761e0a3ab883 100644
--- a/libcxx/test/std/thread/thread.jthread/get_stop_token.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/get_stop_token.pass.cpp
@@ -20,6 +20,7 @@
#include <type_traits>
#include <utility>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(noexcept(std::declval<const std::jthread&>().get_stop_token()));
@@ -27,7 +28,7 @@ static_assert(noexcept(std::declval<const std::jthread&>().get_stop_token()));
int main(int, char**) {
// Represents a thread
{
- std::jthread jt{[] {}};
+ std::jthread jt = support::make_test_jthread([] {});
auto ss = jt.get_stop_source();
std::same_as<std::stop_token> decltype(auto) st = std::as_const(jt).get_stop_token();
diff --git a/libcxx/test/std/thread/thread.jthread/join.deadlock.pass.cpp b/libcxx/test/std/thread/thread.jthread/join.deadlock.pass.cpp
index aa5cdf2783dba04..8e2f1e5f5d9d479 100644
--- a/libcxx/test/std/thread/thread.jthread/join.deadlock.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/join.deadlock.pass.cpp
@@ -31,6 +31,7 @@
#include <type_traits>
#include <vector>
+#include "make_test_thread.h"
#include "test_macros.h"
int main(int, char**) {
@@ -40,12 +41,12 @@ int main(int, char**) {
std::atomic_bool start = false;
std::atomic_bool done = false;
- std::jthread jt{[&] {
+ std::jthread jt = support::make_test_jthread([&] {
start.wait(false);
f();
done = true;
done.notify_all();
- }};
+ });
f = [&] {
try {
diff --git a/libcxx/test/std/thread/thread.jthread/join.pass.cpp b/libcxx/test/std/thread/thread.jthread/join.pass.cpp
index 38986bdfed8d745..2bafd8633824752 100644
--- a/libcxx/test/std/thread/thread.jthread/join.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/join.pass.cpp
@@ -23,6 +23,7 @@
#include <type_traits>
#include <vector>
+#include "make_test_thread.h"
#include "test_macros.h"
int main(int, char**) {
@@ -33,10 +34,10 @@ int main(int, char**) {
constexpr auto numberOfThreads = 10u;
jts.reserve(numberOfThreads);
for (auto i = 0u; i < numberOfThreads; ++i) {
- jts.emplace_back([&] {
+ jts.emplace_back(support::make_test_jthread([&] {
std::this_thread::sleep_for(std::chrono::milliseconds(2));
calledTimes.fetch_add(1, std::memory_order_relaxed);
- });
+ }));
}
for (auto i = 0u; i < numberOfThreads; ++i) {
@@ -55,15 +56,15 @@ int main(int, char**) {
// Synchronization: The completion of the thread represented by *this synchronizes with
// ([intro.multithread]) the corresponding successful join() return.
{
- bool flag = false;
- std::jthread jt{[&] { flag = true; }};
+ bool flag = false;
+ std::jthread jt = support::make_test_jthread([&] { flag = true; });
jt.join();
assert(flag); // non atomic write is visible to the current thread
}
// Postconditions: The thread represented by *this has completed. get_id() == id().
{
- std::jthread jt{[] {}};
+ std::jthread jt = support::make_test_jthread([] {});
assert(jt.get_id() != std::jthread::id());
jt.join();
assert(jt.get_id() == std::jthread::id());
diff --git a/libcxx/test/std/thread/thread.jthread/joinable.pass.cpp b/libcxx/test/std/thread/thread.jthread/joinable.pass.cpp
index 5c0fbece4c21e47..3a88100d934dbfc 100644
--- a/libcxx/test/std/thread/thread.jthread/joinable.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/joinable.pass.cpp
@@ -19,6 +19,7 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(noexcept(std::declval<const std::jthread&>().joinable()));
@@ -33,7 +34,7 @@ int main(int, char**) {
// Non-default constructed
{
- const std::jthread jt{[] {}};
+ const std::jthread jt = support::make_test_jthread([] {});
std::same_as<bool> decltype(auto) result = jt.joinable();
assert(result);
}
@@ -41,8 +42,8 @@ int main(int, char**) {
// Non-default constructed
// the thread of execution has not finished
{
- std::atomic_bool done = false;
- const std::jthread jt{[&done] { done.wait(false); }};
+ std::atomic_bool done = false;
+ const std::jthread jt = support::make_test_jthread([&done] { done.wait(false); });
std::same_as<bool> decltype(auto) result = jt.joinable();
done = true;
done.notify_all();
diff --git a/libcxx/test/std/thread/thread.jthread/request_stop.pass.cpp b/libcxx/test/std/thread/thread.jthread/request_stop.pass.cpp
index f1109561cf9f299..ccbea9f145e504e 100644
--- a/libcxx/test/std/thread/thread.jthread/request_stop.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/request_stop.pass.cpp
@@ -19,6 +19,7 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
static_assert(noexcept(std::declval<std::jthread&>().request_stop()));
@@ -26,8 +27,8 @@ static_assert(noexcept(std::declval<std::jthread&>().request_stop()));
int main(int, char**) {
// Represents a thread
{
- std::jthread jt{[] {}};
- auto st = jt.get_stop_token();
+ std::jthread jt = support::make_test_jthread([] {});
+ auto st = jt.get_stop_token();
assert(!st.stop_requested());
std::same_as<bool> decltype(auto) result = jt.request_stop();
assert(result);
diff --git a/libcxx/test/std/thread/thread.jthread/swap.free.pass.cpp b/libcxx/test/std/thread/thread.jthread/swap.free.pass.cpp
index 776537cdff48358..359dea2a17a9a91 100644
--- a/libcxx/test/std/thread/thread.jthread/swap.free.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/swap.free.pass.cpp
@@ -17,12 +17,14 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
template <class T>
-concept IsFreeSwapNoexcept = requires(T& a, T& b) {
- { swap(a, b) } noexcept;
-};
+concept IsFreeSwapNoexcept =
+ requires(T& a, T& b) {
+ { swap(a, b) } noexcept;
+ };
static_assert(IsFreeSwapNoexcept<std::jthread>);
@@ -30,7 +32,7 @@ int main(int, char**) {
// x is default constructed
{
std::jthread t1;
- std::jthread t2{[] {}};
+ std::jthread t2 = support::make_test_jthread([] {});
const auto originalId2 = t2.get_id();
swap(t1, t2);
@@ -40,7 +42,7 @@ int main(int, char**) {
// y is default constructed
{
- std::jthread t1([] {});
+ std::jthread t1 = support::make_test_jthread([] {});
std::jthread t2{};
const auto originalId1 = t1.get_id();
swap(t1, t2);
@@ -51,8 +53,8 @@ int main(int, char**) {
// both not default constructed
{
- std::jthread t1([] {});
- std::jthread t2{[] {}};
+ std::jthread t1 = support::make_test_jthread([] {});
+ std::jthread t2 = support::make_test_jthread([] {});
const auto originalId1 = t1.get_id();
const auto originalId2 = t2.get_id();
swap(t1, t2);
diff --git a/libcxx/test/std/thread/thread.jthread/swap.member.pass.cpp b/libcxx/test/std/thread/thread.jthread/swap.member.pass.cpp
index 614e3ac8312dab7..b86cc35b9fdbb4e 100644
--- a/libcxx/test/std/thread/thread.jthread/swap.member.pass.cpp
+++ b/libcxx/test/std/thread/thread.jthread/swap.member.pass.cpp
@@ -17,12 +17,14 @@
#include <thread>
#include <type_traits>
+#include "make_test_thread.h"
#include "test_macros.h"
template <class T>
-concept IsMemberSwapNoexcept = requires(T& a, T& b) {
- { a.swap(b) } noexcept;
-};
+concept IsMemberSwapNoexcept =
+ requires(T& a, T& b) {
+ { a.swap(b) } noexcept;
+ };
static_assert(IsMemberSwapNoexcept<std::jthread>);
@@ -30,7 +32,7 @@ int main(int, char**) {
// this is default constructed
{
std::jthread t1;
- std::jthread t2{[] {}};
+ std::jthread t2 = support::make_test_jthread([] {});
const auto originalId2 = t2.get_id();
t1.swap(t2);
@@ -40,7 +42,7 @@ int main(int, char**) {
// that is default constructed
{
- std::jthread t1([] {});
+ std::jthread t1 = support::make_test_jthread([] {});
std::jthread t2{};
const auto originalId1 = t1.get_id();
t1.swap(t2);
@@ -51,8 +53,8 @@ int main(int, char**) {
// both not default constructed
{
- std::jthread t1([] {});
- std::jthread t2{[] {}};
+ std::jthread t1 = support::make_test_jthread([] {});
+ std::jthread t2 = support::make_test_jthread([] {});
const auto originalId1 = t1.get_id();
const auto originalId2 = t2.get_id();
t1.swap(t2);
diff --git a/libcxx/test/support/make_test_thread.h b/libcxx/test/support/make_test_thread.h
index eaf967e2180ede8..6cbdf31c08edd22 100644
--- a/libcxx/test/support/make_test_thread.h
+++ b/libcxx/test/support/make_test_thread.h
@@ -12,13 +12,34 @@
#include <thread>
#include <utility>
+#include "test_macros.h"
+
namespace support {
+// These functions are used to mock the creation of threads within the test suite.
+//
+// This provides a vendor-friendly way of making the test suite work even on platforms
+// where the standard thread constructors don't work (e.g. embedded environments where
+// creating a thread requires additional information like setting attributes).
+//
+// Vendors can keep a downstream diff in this file to create threads however they
+// need on their platform, and the majority of the test suite will work out of the
+// box. Of course, tests that exercise the standard thread constructors won't work,
+// but any other test that only creates threads as a side effect of testing should
+// work if they use the utilities in this file.
+
template <class F, class ...Args>
std::thread make_test_thread(F&& f, Args&& ...args) {
return std::thread(std::forward<F>(f), std::forward<Args>(args)...);
}
+#if TEST_STD_VER >= 20
+template <class F, class ...Args>
+std::jthread make_test_jthread(F&& f, Args&& ...args) {
+ return std::jthread(std::forward<F>(f), std::forward<Args>(args)...);
+}
+#endif
+
} // end namespace support
#endif // TEST_SUPPORT_MAKE_TEST_THREAD_H
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
995fcd3
to
ae7b50b
Compare
This patch introduces the support::make_test_jthread utility which is basically the same as support::make_test_thread but for std::jthread. It allows vendors to maintain a downstream way to create threads for use within the test suite, which is especially useful for embedded platforms.
ae7b50b
to
10d05d9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I noticed that not all tests are updated. For example
cons.default.pass.cpp
cons.func.token.pass.cpp
are unchanged. Is this intentional?
Yes, this is intentional. Those tests are testing specifically the constructors, so it is intended for them to fail on platforms where the constructors are not supported. |
This patch introduces the support::make_test_jthread utility which is basically the same as support::make_test_thread but for std::jthread. It allows vendors to maintain a downstream way to create threads for use within the test suite, which is especially useful for embedded platforms.