ThreadPool follow-ups, proactive shutdown and HasReason dependency cleanup#34562
ThreadPool follow-ups, proactive shutdown and HasReason dependency cleanup#34562achow101 merged 11 commits intobitcoin:masterfrom
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. LLM Linter (✨ experimental)Possible typos and grammar issues:
No other typos were found. 2026-02-26 14:30:33 |
ddf2273 to
adaf571
Compare
seduless
left a comment
There was a problem hiding this comment.
Reviewed adaf571
While testing, I noticed that commenting out while (ProcessTask()) {} in Stop() doesn't cause any test failures, so the active-wait drain behavior isn't currently covered by the test suite. Here's a test that exercises it by verifying the calling thread processes queued tasks during Stop(), and provably fails if the active-wait is removed:
BOOST_AUTO_TEST_CASE(stop_active_wait_drains_queue)
{
ThreadPool threadPool(POOL_NAME);
threadPool.Start(NUM_WORKERS_DEFAULT);
std::counting_semaphore<> blocker(0);
const auto blocking_tasks = BlockWorkers(threadPool, blocker, NUM_WORKERS_DEFAULT);
auto main_thread_id = std::this_thread::get_id();
std::atomic<int> main_thread_tasks{0};
const int num_tasks = 20;
for (int i = 0; i < num_tasks; i++) {
(void)Submit(threadPool, [&main_thread_tasks, main_thread_id]() {
if (std::this_thread::get_id() == main_thread_id)
main_thread_tasks.fetch_add(1, std::memory_order_relaxed);
});
}
BOOST_CHECK_EQUAL(threadPool.WorkQueueSize(), static_cast<size_t>(num_tasks));
// Delay release so Stop() has a window to drain tasks from the calling thread
std::thread unblocker([&blocker]() {
UninterruptibleSleep(300ms);
blocker.release(NUM_WORKERS_DEFAULT);
});
threadPool.Stop();
unblocker.join();
BOOST_CHECK_GT(main_thread_tasks.load(), 0);
WAIT_FOR(blocking_tasks);
}adaf571 to
4c6cdb0
Compare
|
@seduless, just pushed the test with a few small modifications. Since you haven't contributed to any repository yet, I couldn't find your email to add you as the commit author. You can send it to me via IRC or leaving a comment here, and I'll give you authorship. |
b2d2db5 to
c919959
Compare
|
@furszy Thanks! Appreciate it: |
c919959 to
5561d0c
Compare
|
@seduless done. Feel very welcome to keep reviewing! |
|
ACK 566f7f8 |
maflcko
left a comment
There was a problem hiding this comment.
lgtm, but I think the DEBUG_LOG_OUT regression should not be hidden, and probably reverted.
review ACK 566f7f8 🔭
Show signature
Signature:
untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: review ACK 566f7f81de967065afebc153ec41dc7b8d8300d0 🔭
djAJqobfVijAJhOWxsBW8FcWoW6+27+15S5YpVNGfATR3dMyeVI0VKItWZUCTQjN3RbjDvRiymA04OyDpnk4Dg==
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Instead of waiting for the workers to finish processing tasks, help them actively inside Stop(). This speeds up the JSON-RPC and REST server shutdown procedure, and results in a faster node shutdown when many requests remain unhandled
Exercise the case where tasks remain pending and verify that the thread calling Stop() participates in draining the queue
566f7f8 to
775d6d6
Compare
|
Updated per feedback, thanks @maflcko. |
|
775d6d6 🕹 Show signatureSignature: |
Move the operator<< overloads used by BOOST_CHECK_* out of the unit test machinery test/setup_common, into test/util/common.h. And replace the individual per-type ToString() overloads with a single concept-constrained template that covers any type exposing a ToString() method. This is important to not add uint256.h and transaction_identifier.h dependencies to the shared test/util/common.h file. Co-authored-by: furszy <matiasfurszyfer@protonmail.com>
Avoid providing the entire unit test framework dependency to tests that only require access to the HasReason utility class. E.g. reverselock_tests.cpp, sync_tests.cpp, util_check_tests.cpp, util_string_tests.cpp, and script_parse_tests.cpp only require access to HasReason and nothing else.
Submit tasks to a non-started, interrupted, or stopped pool and verify the proper error is always returned.
Useful for debugging issues. Co-authored-by: Matias Furszyfer <matiasfurszyfer@protonmail.com>
775d6d6 to
408d5b1
Compare
|
review ACK 408d5b1 🕗 Show signatureSignature: |
|
ACK 408d5b1 |
A few follow-ups to #33689, includes:
ThreadPoolactive-wait during shutdown:Instead of just waiting for workers to finish processing tasks,
Stop()now helps them actively.This speeds up the JSON-RPC and REST server shutdown, resulting in a faster node shutdown when many requests remain unhandled. This wasn't included in the original PR due to the behavior change this introduces.
Decouple
HasReasonfrom the unit test framework machineryThis avoids providing the entire unit test framework dependency to low-level tests that only require access to the
HasReasonutility class. Examples are:reverselock_tests.cpp,sync_tests.cpp,util_check_tests.cpp,util_string_tests.cpp,script_parse_tests.cppandthreadpool_tests.cpp. These tests no longer gain access to unnecessary components like the chainstate, node context, caches, etc. It includes l0rinc'sthreadpool_tests.cppHasReasonchanges.Include response body in non-JSON HTTP error messages
Straight from pinheadmz comment, it makes debugging CI issues easier.