Coverage Report

Created: 2020-02-14 15:38

/src/botan/src/lib/utils/thread_utils/thread_pool.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2019 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
12
namespace Botan {
13
14
//static
15
Thread_Pool& Thread_Pool::global_instance()
16
0
   {
17
0
   static Thread_Pool g_thread_pool(OS::read_env_variable_sz("BOTAN_THREAD_POOL_SIZE"));
18
0
   return g_thread_pool;
19
0
   }
20
21
Thread_Pool::Thread_Pool(size_t pool_size)
22
0
   {
23
0
   if(pool_size == 0)
24
0
      {
25
0
      pool_size = OS::get_cpu_available();
26
0
27
0
      /*
28
0
      * For large machines don't create too many threads, unless
29
0
      * explicitly asked to by the caller.
30
0
      */
31
0
      if(pool_size > 16)
32
0
         pool_size = 16;
33
0
      }
34
0
35
0
   if(pool_size <= 1)
36
0
      pool_size = 2;
37
0
38
0
   m_shutdown = false;
39
0
40
0
   for(size_t i = 0; i != pool_size; ++i)
41
0
      {
42
0
      m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this));
43
0
      }
44
0
   }
45
46
void Thread_Pool::shutdown()
47
0
   {
48
0
      {
49
0
      std::unique_lock<std::mutex> lock(m_mutex);
50
0
51
0
      if(m_shutdown == true)
52
0
         return;
53
0
54
0
      m_shutdown = true;
55
0
56
0
      m_more_tasks.notify_all();
57
0
      }
58
0
59
0
   for(auto&& thread : m_workers)
60
0
      {
61
0
      thread.join();
62
0
      }
63
0
   m_workers.clear();
64
0
   }
65
66
void Thread_Pool::queue_thunk(std::function<void ()> fn)
67
0
   {
68
0
   std::unique_lock<std::mutex> lock(m_mutex);
69
0
70
0
   if(m_shutdown)
71
0
      throw Invalid_State("Cannot add work after thread pool has shut down");
72
0
73
0
   m_tasks.push_back(fn);
74
0
   m_more_tasks.notify_one();
75
0
   }
76
77
void Thread_Pool::worker_thread()
78
0
   {
79
0
   for(;;)
80
0
      {
81
0
      std::function<void()> task;
82
0
83
0
         {
84
0
         std::unique_lock<std::mutex> lock(m_mutex);
85
0
         m_more_tasks.wait(lock, [this]{ return m_shutdown || !m_tasks.empty(); });
86
0
87
0
         if(m_tasks.empty())
88
0
            {
89
0
            if(m_shutdown)
90
0
               return;
91
0
            else
92
0
               continue;
93
0
            }
94
0
95
0
         task = m_tasks.front();
96
0
         m_tasks.pop_front();
97
0
         }
98
0
99
0
      task();
100
0
      }
101
0
   }
102
103
}