util/ carries no wire surface, so it lands before the contract freeze. - error: enum class Error, the engine-wide failure taxonomy; is_retryable enumerates every value (no default:) so -Wswitch forces the retry decision on each future addition. ErrorInfo carries context/http_status. - result: Result<T> over std::expected<T, ErrorInfo>, Result<void>, VDM_TRY / VDM_TRY_ASSIGN. Errors returned, never thrown, on the transfer path. - bytes: span aliases, LE load_le/store_le (debug-asserted precondition, not input validation), and a bounds-checked latching ByteReader for the .veloxpart.meta reader. - event_bus: typed thread-safe pub/sub; header states plainly that unsubscribe is not a quiesce point and download_task will need its own drain. - thread_pool: std::jthread pool; dtor joins in the body before members die (fixed a use-after-destruction on cv_/mu_). Header notes shutdown is drain-only and DAEMON will need a cancel mode. - log: sink interface (core does no I/O); DAEMON installs one. Tested: -Werror clean, 6 binaries green under plain / ASan+UBSan / TSan. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HPPSGhiArbvQgwC2DNiURS
50 lines
1.3 KiB
C++
50 lines
1.3 KiB
C++
// vdm/util/thread_pool.cpp
|
|
|
|
#include "vdm/util/thread_pool.hpp"
|
|
|
|
namespace vdm {
|
|
|
|
ThreadPool::ThreadPool(std::size_t threads) {
|
|
if (threads == 0) {
|
|
threads = std::thread::hardware_concurrency();
|
|
if (threads == 0)
|
|
threads = 1;
|
|
}
|
|
workers_.reserve(threads);
|
|
for (std::size_t i = 0; i < threads; ++i)
|
|
workers_.emplace_back([this] { worker_loop(); });
|
|
}
|
|
|
|
ThreadPool::~ThreadPool() {
|
|
{
|
|
std::lock_guard lk(mu_);
|
|
stopping_ = true;
|
|
}
|
|
cv_.notify_all();
|
|
// Join here, in the destructor body, while mu_/cv_/jobs_ are still alive. Relying on
|
|
// std::jthread's implicit join would run it during member destruction — after cv_ and
|
|
// mu_ are already gone, which the workers are still touching.
|
|
for (auto &w : workers_)
|
|
w.join();
|
|
workers_.clear();
|
|
}
|
|
|
|
void ThreadPool::worker_loop() {
|
|
for (;;) {
|
|
std::function<void()> job;
|
|
{
|
|
std::unique_lock lk(mu_);
|
|
cv_.wait(lk, [this] { return stopping_ || !jobs_.empty(); });
|
|
if (jobs_.empty()) {
|
|
// Only reached when stopping_ and nothing left to do.
|
|
return;
|
|
}
|
|
job = std::move(jobs_.front());
|
|
jobs_.pop();
|
|
}
|
|
job();
|
|
}
|
|
}
|
|
|
|
} // namespace vdm
|