test: coverage for queued tasks completion after interrupt
What changed, and why it matters
This commit only adds a new automated test to Bitcoin Core. It checks that a worker thread pool still finishes tasks that were already waiting in line after the pool is told to stop accepting new work (Interrupt). There is no change to production code and no security fix or vulnerability patch.
No security action needed; treat as routine test-coverage improvement. Review the related ThreadPool implementation only if this test fails in CI.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff adds BOOST_AUTO_TEST_CASE(queued_tasks_complete_after_interrupt) in src/test/threadpool_tests.cpp. It verifies that tasks already queued to ThreadPool are executed even after Interrupt() is called, by blocking all workers, submitting 10 counting tasks, calling Interrupt(), then releasing the workers and asserting counter == 10. No ThreadPool implementation code is modified.
Changed components
src/test/threadpool_tests.cppInspect captured patch +29 / −0
diff --git a/src/test/threadpool_tests.cpp b/src/test/threadpool_tests.cpp
index d956c205..4855b334 100644
--- a/src/test/threadpool_tests.cpp
+++ b/src/test/threadpool_tests.cpp
@@ -38,6 +38,7 @@ struct ThreadPoolFixture {
// 9) Congestion test; create more workers than available cores.
// 10) Ensure Interrupt() prevents further submissions.
// 11) Start() must not cause a deadlock when called during Stop().
+// 12) Ensure queued tasks complete after Interrupt().
BOOST_FIXTURE_TEST_SUITE(threadpool_tests, ThreadPoolFixture)
#define WAIT_FOR(futures) \
@@ -351,4 +352,32 @@ BOOST_AUTO_TEST_CASE(start_mid_stop_does_not_deadlock)
stopper_thread.join();
}
+// Test 12, queued tasks complete after Interrupt()
+BOOST_AUTO_TEST_CASE(queued_tasks_complete_after_interrupt)
+{
+ ThreadPool threadPool(POOL_NAME);
+ threadPool.Start(NUM_WORKERS_DEFAULT);
+
+ std::counting_semaphore<> blocker(0);
+ const auto blocking_tasks = BlockWorkers(threadPool, blocker, NUM_WORKERS_DEFAULT);
+
+ // Queue tasks while all workers are busy, then interrupt
+ std::atomic<int> counter{0};
+ const int num_tasks = 10;
+ std::vector<std::future<void>> futures;
+ futures.reserve(num_tasks);
+ for (int i = 0; i < num_tasks; i++) {
+ futures.emplace_back(Submit(threadPool, [&counter]{ counter.fetch_add(1, std::memory_order_relaxed); }));
+ }
+ threadPool.Interrupt();
+
+ // Queued tasks must still complete despite the interrupt
+ blocker.release(NUM_WORKERS_DEFAULT);
+ WAIT_FOR(futures);
+ BOOST_CHECK_EQUAL(counter.load(), num_tasks);
+
+ threadPool.Stop();
+ WAIT_FOR(blocking_tasks);
+}
+
BOOST_AUTO_TEST_SUITE_END()
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.