Botan 3.0.0
Crypto and TLS for C&
thread_pool.cpp
Go to the documentation of this file.
1/*
2* (C) 2019,2021 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/thread_pool.h>
8#include <botan/internal/os_utils.h>
9#include <botan/exceptn.h>
10#include <thread>
11
12namespace Botan {
13
14namespace {
15
16std::optional<size_t> global_thread_pool_size()
17 {
18 std::string var;
19 if(OS::read_env_variable(var, "BOTAN_THREAD_POOL_SIZE"))
20 {
21 try
22 {
23 return std::optional<size_t>(std::stoul(var, nullptr));
24 }
25 catch(std::exception&) { /* ignore it */ }
26
27 if(var == "none")
28 return std::nullopt;
29 }
30
31 // If it was neither a number nor a special value, then ignore it.
32 return std::optional<size_t>(0);
33 }
34
35}
36
37//static
39 {
40 static Thread_Pool g_thread_pool(global_thread_pool_size());
41 return g_thread_pool;
42 }
43
44Thread_Pool::Thread_Pool(std::optional<size_t> opt_pool_size)
45 {
46 m_shutdown = false;
47
48 if(!opt_pool_size.has_value())
49 return;
50
51 size_t pool_size = opt_pool_size.value();
52
53 if(pool_size == 0)
54 {
55 pool_size = OS::get_cpu_available();
56
57 // Unclear if this can happen, but be defensive
58 if(pool_size == 0)
59 pool_size = 2;
60
61 /*
62 * For large machines don't create too many threads, unless
63 * explicitly asked to by the caller.
64 */
65 if(pool_size > 16)
66 pool_size = 16;
67 }
68
69 for(size_t i = 0; i != pool_size; ++i)
70 {
71 m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this));
72 }
73 }
74
76 {
77 {
78 std::unique_lock<std::mutex> lock(m_mutex);
79
80 if(m_shutdown == true)
81 return;
82
83 m_shutdown = true;
84
85 m_more_tasks.notify_all();
86 }
87
88 for(auto&& thread : m_workers)
89 {
90 thread.join();
91 }
92 m_workers.clear();
93 }
94
95void Thread_Pool::queue_thunk(const std::function<void ()>& fn)
96 {
97 std::unique_lock<std::mutex> lock(m_mutex);
98
99 if(m_shutdown)
100 throw Invalid_State("Cannot add work after thread pool has shut down");
101
102 if(m_workers.empty())
103 {
104 return fn();
105 }
106
107 m_tasks.push_back(fn);
108 m_more_tasks.notify_one();
109 }
110
111void Thread_Pool::worker_thread()
112 {
113 for(;;)
114 {
115 std::function<void()> task;
116
117 {
118 std::unique_lock<std::mutex> lock(m_mutex);
119 m_more_tasks.wait(lock, [this]{ return m_shutdown || !m_tasks.empty(); });
120
121 if(m_tasks.empty())
122 {
123 if(m_shutdown)
124 return;
125 else
126 continue;
127 }
128
129 task = m_tasks.front();
130 m_tasks.pop_front();
131 }
132
133 task();
134 }
135 }
136
137}
void queue_thunk(const std::function< void()> &)
Definition: thread_pool.cpp:95
Thread_Pool(std::optional< size_t > pool_size)
Definition: thread_pool.cpp:44
static Thread_Pool & global_instance()
Definition: thread_pool.cpp:38
size_t BOTAN_TEST_API get_cpu_available()
Definition: os_utils.cpp:238
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition: os_utils.cpp:422
Definition: alg_id.cpp:12
secure_vector< T > lock(const std::vector< T > &in)
Definition: secmem.h:71