Skip to content

Commit

Permalink
[libc++] Introduce make_test_jthread for jthread tests (#68837)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ldionne authored Oct 13, 2023
1 parent 158c052 commit 475e154
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 52 deletions.
37 changes: 19 additions & 18 deletions libcxx/test/std/thread/thread.jthread/assign.move.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,31 @@
#include <utility>
#include <vector>

#include "make_test_thread.h"
#include "test_macros.h"

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);
}

// 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);
}

Expand All @@ -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) {
Expand All @@ -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);

Expand All @@ -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());
Expand All @@ -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();

Expand Down
9 changes: 5 additions & 4 deletions libcxx/test/std/thread/thread.jthread/cons.move.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>);
Expand All @@ -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());
Expand All @@ -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());
Expand Down
7 changes: 4 additions & 3 deletions libcxx/test/std/thread/thread.jthread/detach.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@
#include <thread>
#include <type_traits>

#include "make_test_thread.h"
#include "test_macros.h"

int main(int, char**) {
// Effects: The thread represented by *this continues execution without the calling thread blocking.
{
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();
Expand All @@ -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());
Expand Down
10 changes: 6 additions & 4 deletions libcxx/test/std/thread/thread.jthread/dtor.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <thread>
#include <type_traits>
#include <vector>

#include "make_test_thread.h"
#include "test_macros.h"

int main(int, char**) {
Expand All @@ -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);
Expand All @@ -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();

Expand Down
3 changes: 2 additions & 1 deletion libcxx/test/std/thread/thread.jthread/get_id.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand All @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
#include <thread>
#include <type_traits>

#include "make_test_thread.h"
#include "test_macros.h"

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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
#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()));

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();

Expand Down
5 changes: 3 additions & 2 deletions libcxx/test/std/thread/thread.jthread/join.deadlock.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <type_traits>
#include <vector>

#include "make_test_thread.h"
#include "test_macros.h"

int main(int, char**) {
Expand All @@ -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 {
Expand Down
11 changes: 6 additions & 5 deletions libcxx/test/std/thread/thread.jthread/join.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <type_traits>
#include <vector>

#include "make_test_thread.h"
#include "test_macros.h"

int main(int, char**) {
Expand All @@ -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) {
Expand All @@ -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());
Expand Down
7 changes: 4 additions & 3 deletions libcxx/test/std/thread/thread.jthread/joinable.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand All @@ -33,16 +34,16 @@ 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);
}

// 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();
Expand Down
5 changes: 3 additions & 2 deletions libcxx/test/std/thread/thread.jthread/request_stop.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
#include <thread>
#include <type_traits>

#include "make_test_thread.h"
#include "test_macros.h"

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);
Expand Down
9 changes: 5 additions & 4 deletions libcxx/test/std/thread/thread.jthread/swap.free.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <thread>
#include <type_traits>

#include "make_test_thread.h"
#include "test_macros.h"

template <class T>
Expand All @@ -30,7 +31,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);

Expand All @@ -40,7 +41,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);
Expand All @@ -51,8 +52,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);
Expand Down
Loading

0 comments on commit 475e154

Please sign in to comment.