mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-05 23:59:49 +00:00
LibThreading: ThreadPool deadlock test
Enable `LibThreading` tests and add a test to check for deadlocks in `ThreadPool`s
This commit is contained in:
parent
8d336d2a25
commit
a94bf9bd09
Notes:
github-actions[bot]
2024-08-19 01:09:00 +00:00
Author: https://github.com/braydnm
Commit: a94bf9bd09
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/929
Reviewed-by: https://github.com/alimpfard
4 changed files with 60 additions and 0 deletions
|
@ -514,6 +514,7 @@ if (BUILD_TESTING)
|
||||||
LibCompress
|
LibCompress
|
||||||
LibTest
|
LibTest
|
||||||
LibTextCodec
|
LibTextCodec
|
||||||
|
LibThreading
|
||||||
LibUnicode
|
LibUnicode
|
||||||
LibURL
|
LibURL
|
||||||
LibXML
|
LibXML
|
||||||
|
|
|
@ -2,6 +2,7 @@ group("Tests") {
|
||||||
deps = [
|
deps = [
|
||||||
"//Tests/AK",
|
"//Tests/AK",
|
||||||
"//Tests/LibJS",
|
"//Tests/LibJS",
|
||||||
|
"//Tests/LibThreading",
|
||||||
"//Tests/LibURL",
|
"//Tests/LibURL",
|
||||||
"//Tests/LibWeb",
|
"//Tests/LibWeb",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
TestThread.cpp
|
TestThread.cpp
|
||||||
|
TestThreadPool.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach(source IN LISTS TEST_SOURCES)
|
foreach(source IN LISTS TEST_SOURCES)
|
||||||
|
|
57
Tests/LibThreading/TestThreadPool.cpp
Normal file
57
Tests/LibThreading/TestThreadPool.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue