[libcxx-commits] [libcxx] [libc++] Introduce make_test_jthread for jthread tests (PR #68837)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Oct 11 14:42:45 PDT 2023
https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/68837
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.
>From 995fcd34c3b5155d7bcf6c4c2019d88a940a61f3 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 11 Oct 2023 14:39:10 -0700
Subject: [PATCH] [libc++] Introduce make_test_jthread for jthread tests
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.
---
.../thread.jthread/assign.move.pass.cpp | 37 ++++++++++---------
.../thread/thread.jthread/cons.move.pass.cpp | 9 +++--
.../std/thread/thread.jthread/detach.pass.cpp | 7 ++--
.../std/thread/thread.jthread/dtor.pass.cpp | 10 +++--
.../std/thread/thread.jthread/get_id.pass.cpp | 3 +-
.../thread.jthread/get_stop_source.pass.cpp | 3 +-
.../thread.jthread/get_stop_token.pass.cpp | 3 +-
.../thread.jthread/join.deadlock.pass.cpp | 5 ++-
.../std/thread/thread.jthread/join.pass.cpp | 11 +++---
.../thread/thread.jthread/joinable.pass.cpp | 7 ++--
.../thread.jthread/request_stop.pass.cpp | 5 ++-
.../thread/thread.jthread/swap.free.pass.cpp | 16 ++++----
.../thread.jthread/swap.member.pass.cpp | 16 ++++----
libcxx/test/support/make_test_thread.h | 21 +++++++++++
14 files changed, 95 insertions(+), 58 deletions(-)
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
More information about the libcxx-commits
mailing list