TestThreadPool.cpp 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /*
  2. * Copyright (c) 2024, Braydn Moore <braydn.moore@uwaterloo.ca>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Time.h>
  7. #include <LibCore/ElapsedTimer.h>
  8. #include <LibTest/TestCase.h>
  9. #include <LibThreading/ThreadPool.h>
  10. using namespace AK::TimeLiterals;
  11. TEST_CASE(thread_pool_deadlock)
  12. {
  13. static constexpr auto RUN_TIMEOUT = 120_sec;
  14. static constexpr u64 NUM_RUNS = 1000;
  15. static constexpr u64 MAX_VALUE = 1 << 15;
  16. for (u64 i = 0; i < NUM_RUNS; ++i) {
  17. u64 expected_value = (MAX_VALUE * (MAX_VALUE + 1)) / 2;
  18. Atomic<u64> sum;
  19. // heap allocate the ThreadPool in case it deadlocks. Exiting in the
  20. // case of a deadlock will purposefully leak memory to avoid calling the
  21. // destructor and hanging the test
  22. auto* thread_pool = new Threading::ThreadPool<u64>(
  23. [&sum](u64 current_val) {
  24. sum += current_val;
  25. });
  26. for (u64 j = 0; j <= MAX_VALUE; ++j) {
  27. thread_pool->submit(j);
  28. }
  29. auto join_thread = Threading::Thread::construct([thread_pool]() -> intptr_t {
  30. thread_pool->wait_for_all();
  31. delete thread_pool;
  32. return 0;
  33. });
  34. join_thread->start();
  35. auto timer = Core::ElapsedTimer::start_new(Core::TimerType::Precise);
  36. while (!join_thread->has_exited() && timer.elapsed_milliseconds() < RUN_TIMEOUT.to_milliseconds())
  37. ;
  38. EXPECT(join_thread->has_exited());
  39. // exit since the current pool is deadlocked and we have no way of
  40. // unblocking the pool other than having the OS teardown the process
  41. // struct
  42. if (!join_thread->has_exited()) {
  43. return;
  44. }
  45. (void)join_thread->join();
  46. EXPECT_EQ(sum.load(), expected_value);
  47. }
  48. }