diff options
-rw-r--r-- | doc/api_ref/env_vars.rst | 5 | ||||
-rw-r--r-- | src/lib/utils/thread_utils/thread_pool.cpp | 50 | ||||
-rw-r--r-- | src/lib/utils/thread_utils/thread_pool.h | 16 |
3 files changed, 60 insertions, 11 deletions
diff --git a/doc/api_ref/env_vars.rst b/doc/api_ref/env_vars.rst index 221a22545..121402637 100644 --- a/doc/api_ref/env_vars.rst +++ b/doc/api_ref/env_vars.rst @@ -6,7 +6,10 @@ library. The variables and their behavior are described here. * ``BOTAN_THREAD_POOL_SIZE`` controls the number of threads which will be created for a thread pool used for some purposes within the library. If not - set then it defaults to the number of CPUs available on the system. + set, or set to 0, then it defaults to the number of CPUs available on the + system. If it is set to the string "none" then the thread pool is disabled; + instead all work passed to the thread pool will be executed immediately + by the calling thread. * ``BOTAN_MLOCK_POOL_SIZE`` controls the total amount of memory which will be locked in memory using ``mlock`` or ``VirtualLock`` and managed in a memory diff --git a/src/lib/utils/thread_utils/thread_pool.cpp b/src/lib/utils/thread_utils/thread_pool.cpp index 405f79585..ce326fdc0 100644 --- a/src/lib/utils/thread_utils/thread_pool.cpp +++ b/src/lib/utils/thread_utils/thread_pool.cpp @@ -1,5 +1,5 @@ /* -* (C) 2019 Jack Lloyd +* (C) 2019,2021 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -11,19 +11,53 @@ namespace Botan { +namespace { + +std::optional<size_t> global_thread_pool_size() + { + std::string var; + if(OS::read_env_variable(var, "BOTAN_THREAD_POOL_SIZE")) + { + try + { + return std::optional<size_t>(std::stoul(var, nullptr)); + } + catch(std::exception&) { /* ignore it */ } + + if(var == "none") + return std::nullopt; + } + + // If it was neither a number nor a special value, then ignore it. + return std::optional<size_t>(0); + } + +} + //static Thread_Pool& Thread_Pool::global_instance() { - static Thread_Pool g_thread_pool(OS::read_env_variable_sz("BOTAN_THREAD_POOL_SIZE")); + static Thread_Pool g_thread_pool(global_thread_pool_size()); return g_thread_pool; } -Thread_Pool::Thread_Pool(size_t pool_size) +Thread_Pool::Thread_Pool(std::optional<size_t> opt_pool_size) { + m_shutdown = false; + + if(!opt_pool_size.has_value()) + return; + + size_t pool_size = opt_pool_size.value(); + if(pool_size == 0) { pool_size = OS::get_cpu_available(); + // Unclear if this can happen, but be defensive + if(pool_size == 0) + pool_size = 2; + /* * For large machines don't create too many threads, unless * explicitly asked to by the caller. @@ -32,11 +66,6 @@ Thread_Pool::Thread_Pool(size_t pool_size) pool_size = 16; } - if(pool_size <= 1) - pool_size = 2; - - m_shutdown = false; - for(size_t i = 0; i != pool_size; ++i) { m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this)); @@ -70,6 +99,11 @@ void Thread_Pool::queue_thunk(std::function<void ()> fn) if(m_shutdown) throw Invalid_State("Cannot add work after thread pool has shut down"); + if(m_workers.empty()) + { + return fn(); + } + m_tasks.push_back(fn); m_more_tasks.notify_one(); } diff --git a/src/lib/utils/thread_utils/thread_pool.h b/src/lib/utils/thread_utils/thread_pool.h index 8f818d1b7..d94a0e75f 100644 --- a/src/lib/utils/thread_utils/thread_pool.h +++ b/src/lib/utils/thread_utils/thread_pool.h @@ -18,6 +18,7 @@ #include <thread> #include <future> #include <condition_variable> +#include <optional> namespace Botan { @@ -32,9 +33,20 @@ class BOTAN_TEST_API Thread_Pool /** * Initialize a thread pool with some number of threads * @param pool_size number of threads in the pool, if 0 - * then some default value is chosen + * then some default value is chosen. If the optional + * is nullopt then the thread pool is disabled; all + * work is executed immediately when queued. */ - Thread_Pool(size_t pool_size = 0); + Thread_Pool(std::optional<size_t> pool_size); + + /** + * Initialize a thread pool with some number of threads + * @param pool_size number of threads in the pool, if 0 + * then some default value is chosen. + */ + Thread_Pool(size_t pool_size = 0) : + Thread_Pool(std::optional<size_t>(pool_size)) + {} ~Thread_Pool() { shutdown(); } |