LibThreading: ThreadPool deadlock test

Enable `LibThreading` tests and add a test to check for deadlocks in
`ThreadPool`s
This commit is contained in:
Braydn 2024-08-01 22:36:43 -04:00 committed by Ali Mohammad Pur
parent 8d336d2a25
commit a94bf9bd09
Notes: github-actions[bot] 2024-08-19 01:09:00 +00:00
4 changed files with 60 additions and 0 deletions

View file

@ -514,6 +514,7 @@ if (BUILD_TESTING)
LibCompress
LibTest
LibTextCodec
LibThreading
LibUnicode
LibURL
LibXML

View file

@ -2,6 +2,7 @@ group("Tests") {
deps = [
"//Tests/AK",
"//Tests/LibJS",
"//Tests/LibThreading",
"//Tests/LibURL",
"//Tests/LibWeb",
]

View file

@ -1,5 +1,6 @@
set(TEST_SOURCES
TestThread.cpp
TestThreadPool.cpp
)
foreach(source IN LISTS TEST_SOURCES)

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024, Braydn Moore <braydn.moore@uwaterloo.ca>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Time.h>
#include <LibCore/ElapsedTimer.h>
#include <LibTest/TestCase.h>
#include <LibThreading/ThreadPool.h>
using namespace AK::TimeLiterals;
TEST_CASE(thread_pool_deadlock)
{
static constexpr auto RUN_TIMEOUT = 120_sec;
static constexpr u64 NUM_RUNS = 1000;
static constexpr u64 MAX_VALUE = 1 << 15;
for (u64 i = 0; i < NUM_RUNS; ++i) {
u64 expected_value = (MAX_VALUE * (MAX_VALUE + 1)) / 2;
Atomic<u64> sum;
// heap allocate the ThreadPool in case it deadlocks. Exiting in the
// case of a deadlock will purposefully leak memory to avoid calling the
// destructor and hanging the test
auto* thread_pool = new Threading::ThreadPool<u64>(
[&sum](u64 current_val) {
sum += current_val;
});
for (u64 j = 0; j <= MAX_VALUE; ++j) {
thread_pool->submit(j);
}
auto join_thread = Threading::Thread::construct([thread_pool]() -> intptr_t {
thread_pool->wait_for_all();
delete thread_pool;
return 0;
});
join_thread->start();
auto timer = Core::ElapsedTimer::start_new(Core::TimerType::Precise);
while (!join_thread->has_exited() && timer.elapsed_milliseconds() < RUN_TIMEOUT.to_milliseconds())
;
EXPECT(join_thread->has_exited());
// exit since the current pool is deadlocked and we have no way of
// unblocking the pool other than having the OS teardown the process
// struct
if (!join_thread->has_exited()) {
return;
}
(void)join_thread->join();
EXPECT_EQ(sum.load(), expected_value);
}
}