7#include <botan/internal/thread_pool.h>
9#include <botan/exceptn.h>
10#include <botan/internal/os_utils.h>
11#include <botan/internal/parsing.h>
12#include <botan/internal/target_info.h>
20std::optional<size_t> global_thread_pool_size() {
40#if defined(BOTAN_TARGET_OS_IS_MINGW)
44#elif defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
50 return std::optional<size_t>(0);
58 static Thread_Pool g_thread_pool(global_thread_pool_size());
64 const std::string tname =
"Botan thread";
66 if(!opt_pool_size.has_value()) {
70 size_t pool_size = opt_pool_size.value();
77 const size_t cores = OS::get_cpu_available();
78 pool_size = std::clamp<size_t>(cores, 2, 16);
81 m_workers.resize(pool_size);
83 for(
size_t i = 0; i != pool_size; ++i) {
84 m_workers[i] = std::thread(&Thread_Pool::worker_thread, this);
85 OS::set_thread_name(m_workers[i], tname);
91 const std::unique_lock<std::mutex>
lock(m_mutex);
99 m_more_tasks.notify_all();
102 for(
auto&& thread : m_workers) {
109 std::unique_lock<std::mutex>
lock(m_mutex);
112 throw Invalid_State(
"Cannot add work after thread pool has shut down");
115 if(m_workers.empty()) {
120 m_tasks.push_back(work);
121 m_more_tasks.notify_one();
124void Thread_Pool::worker_thread() {
126 std::function<void()> task;
129 std::unique_lock<std::mutex>
lock(m_mutex);
130 m_more_tasks.wait(
lock, [
this] {
return m_shutdown || !m_tasks.empty(); });
132 if(m_tasks.empty()) {
140 task = m_tasks.front();
Thread_Pool(std::optional< size_t > pool_size)
void queue_thunk(const std::function< void()> &work)
static Thread_Pool & global_instance()
bool read_env_variable(std::string &value_out, std::string_view var_name)
std::optional< size_t > parse_sz(std::string_view input, bool require_canonical)
secure_vector< T > lock(const std::vector< T > &in)