threadpool: active-wait during shutdown
What changed, and why it matters
This commit changes how Bitcoin Core's internal thread pool shuts down. Instead of the shutdown thread passively waiting for worker threads to finish leftover tasks, it now pitches in and processes tasks itself while workers finish up. The goal is a faster node shutdown when many RPC/REST requests are still queued. The change itself is a performance/cleanup improvement, not a security fix.
No security action required. Treat as a normal performance/refactoring commit. If reviewing further, verify that Stop() is not called from a context where re-entrantly executing tasks could cause unexpected ordering issues during shutdown, but this is a correctness/robustness concern rather than a security vulnerability.
Security signals we found
No security-relevant signal in the diff: no bounds checks, input validation, memory safety, authentication, or cryptographic changes.
Change is purely operational/performance: reducing shutdown time for RPC/REST thread pool.
No bug class (use-after-free, race, deadlock, information leak) is directly addressed by the patch.
Evidence from the diff
In src/util/threadpool.h, Stop() now calls ProcessTask() in a loop on the calling (shutdown) thread until the queue is empty, then joins the workers. ProcessTask() is changed from void to bool so it can signal whether it actually executed a task. The lock scope and queue-empty behavior are otherwise unchanged. This is an active-draining optimization for shutdown latency.
Changed components
src/util/threadpool.hJSON-RPC and REST server shutdown pathInspect captured patch +6 / −2
diff --git a/src/util/threadpool.h b/src/util/threadpool.h
index 6fc29498..ca39afd4 100644
--- a/src/util/threadpool.h
+++ b/src/util/threadpool.h
@@ -139,6 +139,9 @@ public:
threads_to_join.swap(m_workers);
}
m_cv.notify_all();
+ // Help draining queue
+ while (ProcessTask()) {}
+ // Free resources
for (auto& worker : threads_to_join) worker.join();
// Since we currently wait for tasks completion, sanity-check empty queue
@@ -187,18 +190,19 @@ public:
* @brief Execute a single queued task synchronously.
* Removes one task from the queue and executes it on the calling thread.
*/
- void ProcessTask() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
+ bool ProcessTask() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
std::packaged_task<void()> task;
{
LOCK(m_mutex);
- if (m_work_queue.empty()) return;
+ if (m_work_queue.empty()) return false;
// Pop the task
task = std::move(m_work_queue.front());
m_work_queue.pop();
}
task();
+ return true;
}
/**
Why this scored 18/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.