[Base] Remove `Sleep`s from more test cases

Timing dependencies in this tests were causing spurious test failures:
- Create and Run Thread
- Test Thread QueueUserCallback

They have been largely replaced by spin waits.
This commit is contained in:
Joel Linn 2022-02-22 22:11:17 +01:00 committed by Rick Gibbed
parent e75e0eb39c
commit 4ea6e45e0c
1 changed files with 38 additions and 23 deletions

View File

@ -829,18 +829,25 @@ TEST_CASE("Create and Run Thread", "[thread]") {
std::unique_ptr<Thread> thread; std::unique_ptr<Thread> thread;
WaitResult result; WaitResult result;
Thread::CreationParameters params = {}; Thread::CreationParameters params = {};
auto func = [] { Sleep(20ms); }; std::atomic<unsigned int> fence(0);
auto func = [&fence] {
REQUIRE(spin_wait_for(1s, [&] { return fence == 1; }));
fence++;
};
SECTION("Create most basic case of thread") { SECTION("Create most basic case of thread") {
fence = 0;
thread = Thread::Create(params, func); thread = Thread::Create(params, func);
REQUIRE(thread->native_handle() != nullptr); REQUIRE(thread->native_handle() != nullptr);
REQUIRE_NOTHROW(thread->affinity_mask()); REQUIRE_NOTHROW(thread->affinity_mask());
REQUIRE(thread->name().empty()); REQUIRE(thread->name().empty());
result = Wait(thread.get(), false, 50ms); fence++;
result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
} }
SECTION("Add thread name") { SECTION("Add thread name") {
fence = 0;
std::string new_name = "Test thread name"; std::string new_name = "Test thread name";
thread = Thread::Create(params, func); thread = Thread::Create(params, func);
auto name = thread->name(); auto name = thread->name();
@ -848,7 +855,8 @@ TEST_CASE("Create and Run Thread", "[thread]") {
REQUIRE(name.empty()); REQUIRE(name.empty());
thread->set_name(new_name); thread->set_name(new_name);
REQUIRE(thread->name() == new_name); REQUIRE(thread->name() == new_name);
result = Wait(thread.get(), false, 50ms); fence++;
result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
} }
@ -858,10 +866,10 @@ TEST_CASE("Create and Run Thread", "[thread]") {
Sleep(1ms); Sleep(1ms);
} }
}); });
result = Wait(thread.get(), false, 50ms); result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kTimeout); REQUIRE(result == WaitResult::kTimeout);
thread->Terminate(-1); thread->Terminate(-1);
result = Wait(thread.get(), false, 50ms); result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
} }
@ -869,8 +877,10 @@ TEST_CASE("Create and Run Thread", "[thread]") {
thread = Thread::Create(params, [] { thread = Thread::Create(params, [] {
Thread::Exit(-1); Thread::Exit(-1);
FAIL("Function must not return"); FAIL("Function must not return");
while (true)
;
}); });
result = Wait(thread.get(), false, 50ms); result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
} }
@ -879,14 +889,16 @@ TEST_CASE("Create and Run Thread", "[thread]") {
REQUIRE(result == WaitResult::kTimeout); REQUIRE(result == WaitResult::kTimeout);
} }
SECTION("16kb stack size") { SECTION("16Mb stack size") {
params.stack_size = 16_MiB; params.stack_size = 16_MiB;
thread = Thread::Create(params, [] { thread = Thread::Create(params, [] {
Thread::Exit(-1); Thread::Exit(-1);
FAIL("Function must not return"); FAIL("Function must not return");
while (true)
;
}); });
REQUIRE(thread != nullptr); REQUIRE(thread != nullptr);
result = Wait(thread.get(), false, 50ms); result = Wait(thread.get(), false, 1s);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
} }
@ -973,18 +985,19 @@ TEST_CASE("Test Thread QueueUserCallback", "[thread]") {
has_finished = -1; has_finished = -1;
thread = Thread::Create(params, [&has_finished, &order] { thread = Thread::Create(params, [&has_finished, &order] {
// Not using Alertable so callback is not registered // Not using Alertable so callback is not registered
order++; // 1
Sleep(90ms); Sleep(90ms);
order++; // 2
has_finished = std::atomic_fetch_add_explicit( has_finished = std::atomic_fetch_add_explicit(
&order, 1, std::memory_order::memory_order_relaxed); &order, 1, std::memory_order::memory_order_relaxed);
}); });
result = Wait(thread.get(), true, 50ms); REQUIRE(!spin_wait_for(50ms, [&] { return order == 2; }));
REQUIRE(result == WaitResult::kTimeout);
REQUIRE(is_modified == -1); REQUIRE(is_modified == -1);
thread->QueueUserCallback(callback); thread->QueueUserCallback(callback);
result = Wait(thread.get(), true, 100ms); result = Wait(thread.get(), true, 200ms);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
REQUIRE(is_modified == -1); REQUIRE(is_modified == -1);
REQUIRE(has_finished == 0); REQUIRE(has_finished == 2);
// With alertable // With alertable
order = 0; order = 0;
@ -992,18 +1005,19 @@ TEST_CASE("Test Thread QueueUserCallback", "[thread]") {
has_finished = -1; has_finished = -1;
thread = Thread::Create(params, [&has_finished, &order] { thread = Thread::Create(params, [&has_finished, &order] {
// Using Alertable so callback is registered // Using Alertable so callback is registered
order++; // 1
AlertableSleep(90ms); AlertableSleep(90ms);
order++; // 3
has_finished = std::atomic_fetch_add_explicit( has_finished = std::atomic_fetch_add_explicit(
&order, 1, std::memory_order::memory_order_relaxed); &order, 1, std::memory_order::memory_order_relaxed);
}); });
result = Wait(thread.get(), true, 50ms); REQUIRE(!spin_wait_for(50ms, [&] { return order == 2; }));
REQUIRE(result == WaitResult::kTimeout);
REQUIRE(is_modified == -1); REQUIRE(is_modified == -1);
thread->QueueUserCallback(callback); thread->QueueUserCallback(callback);
result = Wait(thread.get(), true, 100ms); result = Wait(thread.get(), true, 200ms);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
REQUIRE(is_modified == 0); REQUIRE(is_modified == 1);
REQUIRE(has_finished == 1); REQUIRE(has_finished == 3);
// Test Exit command with QueueUserCallback // Test Exit command with QueueUserCallback
order = 0; order = 0;
@ -1013,17 +1027,18 @@ TEST_CASE("Test Thread QueueUserCallback", "[thread]") {
is_modified = std::atomic_fetch_add_explicit( is_modified = std::atomic_fetch_add_explicit(
&order, 1, std::memory_order::memory_order_relaxed); &order, 1, std::memory_order::memory_order_relaxed);
// Using Alertable so callback is registered // Using Alertable so callback is registered
AlertableSleep(200ms); order++; // 2
has_finished = std::atomic_fetch_add_explicit( AlertableSleep(1s);
&order, 1, std::memory_order::memory_order_relaxed); FAIL("Thread should have been terminated during alertable sleep");
while (true)
;
}); });
result = Wait(thread.get(), true, 100ms); REQUIRE(!spin_wait_for(100ms, [&] { return order == 3; })); // timeout
REQUIRE(result == WaitResult::kTimeout);
thread->QueueUserCallback([] { Thread::Exit(0); }); thread->QueueUserCallback([] { Thread::Exit(0); });
result = Wait(thread.get(), true, 500ms); result = Wait(thread.get(), true, 500ms);
REQUIRE(result == WaitResult::kSuccess); REQUIRE(result == WaitResult::kSuccess);
REQUIRE(is_modified == 0); REQUIRE(is_modified == 0);
REQUIRE(has_finished == -1); REQUIRE(order == 2);
// TODO(bwrsandman): Test alertable wait returning kUserCallback by using IO // TODO(bwrsandman): Test alertable wait returning kUserCallback by using IO
// callbacks. // callbacks.