]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdbsupport/thread-pool.h
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdbsupport / thread-pool.h
CommitLineData
a0b57563
CB
1/* Thread pool
2
1d506c26 3 Copyright (C) 2019-2024 Free Software Foundation, Inc.
a0b57563
CB
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#ifndef GDBSUPPORT_THREAD_POOL_H
21#define GDBSUPPORT_THREAD_POOL_H
22
23#include <queue>
a0b57563
CB
24#include <vector>
25#include <functional>
307733cc 26#include <chrono>
0981fe10
TT
27#if CXX_STD_THREAD
28#include <thread>
a0b57563
CB
29#include <mutex>
30#include <condition_variable>
31#include <future>
20c4eb42 32#endif
6b09f134 33#include <optional>
a0b57563
CB
34
35namespace gdb
36{
37
20c4eb42
TT
38#if CXX_STD_THREAD
39
40/* Simply use the standard future. */
41template<typename T>
42using future = std::future<T>;
43
307733cc
TT
44/* ... and the standard future_status. */
45using future_status = std::future_status;
46
20c4eb42
TT
47#else /* CXX_STD_THREAD */
48
307733cc
TT
49/* A compatibility enum for std::future_status. This is just the
50 subset needed by gdb. */
51enum class future_status
52{
53 ready,
54 timeout,
55};
56
20c4eb42
TT
57/* A compatibility wrapper for std::future. Once <thread> and
58 <future> are available in all GCC builds -- should that ever happen
59 -- this can be removed. GCC does not implement threading for
60 MinGW, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687.
61
62 Meanwhile, in this mode, there are no threads. Tasks submitted to
63 the thread pool are invoked immediately and their result is stored
64 here. The base template here simply wraps a T and provides some
65 std::future compatibility methods. The provided methods are chosen
66 based on what GDB needs presently. */
67
68template<typename T>
69class future
70{
71public:
72
73 explicit future (T value)
74 : m_value (std::move (value))
75 {
76 }
77
78 future () = default;
79 future (future &&other) = default;
80 future (const future &other) = delete;
81 future &operator= (future &&other) = default;
82 future &operator= (const future &other) = delete;
83
84 void wait () const { }
85
307733cc
TT
86 template<class Rep, class Period>
87 future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
88 const
89 {
90 return future_status::ready;
91 }
92
20c4eb42
TT
93 T get () { return std::move (m_value); }
94
95private:
96
97 T m_value;
98};
99
100/* A specialization for void. */
101
102template<>
103class future<void>
104{
105public:
106 void wait () const { }
307733cc
TT
107
108 template<class Rep, class Period>
109 future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
110 const
111 {
112 return future_status::ready;
113 }
114
20c4eb42
TT
115 void get () { }
116};
117
118#endif /* CXX_STD_THREAD */
119
120
a0b57563
CB
121/* A thread pool.
122
123 There is a single global thread pool, see g_thread_pool. Tasks can
124 be submitted to the thread pool. They will be processed in worker
125 threads as time allows. */
126class thread_pool
127{
128public:
129 /* The sole global thread pool. */
130 static thread_pool *g_thread_pool;
131
132 ~thread_pool ();
133 DISABLE_COPY_AND_ASSIGN (thread_pool);
134
135 /* Set the thread count of this thread pool. By default, no threads
136 are created -- the thread count must be set first. */
137 void set_thread_count (size_t num_threads);
138
139 /* Return the number of executing threads. */
140 size_t thread_count () const
141 {
0981fe10 142#if CXX_STD_THREAD
a0b57563 143 return m_thread_count;
0981fe10
TT
144#else
145 return 0;
146#endif
a0b57563
CB
147 }
148
149 /* Post a task to the thread pool. A future is returned, which can
150 be used to wait for the result. */
20c4eb42 151 future<void> post_task (std::function<void ()> &&func)
f4565e4c 152 {
20c4eb42 153#if CXX_STD_THREAD
f4565e4c 154 std::packaged_task<void ()> task (std::move (func));
20c4eb42 155 future<void> result = task.get_future ();
f4565e4c
TT
156 do_post_task (std::packaged_task<void ()> (std::move (task)));
157 return result;
20c4eb42
TT
158#else
159 func ();
160 return {};
161#endif /* CXX_STD_THREAD */
f4565e4c
TT
162 }
163
164 /* Post a task to the thread pool. A future is returned, which can
165 be used to wait for the result. */
166 template<typename T>
20c4eb42 167 future<T> post_task (std::function<T ()> &&func)
f4565e4c 168 {
20c4eb42 169#if CXX_STD_THREAD
f4565e4c 170 std::packaged_task<T ()> task (std::move (func));
20c4eb42 171 future<T> result = task.get_future ();
f4565e4c
TT
172 do_post_task (std::packaged_task<void ()> (std::move (task)));
173 return result;
20c4eb42
TT
174#else
175 return future<T> (func ());
176#endif /* CXX_STD_THREAD */
f4565e4c 177 }
a0b57563
CB
178
179private:
180
181 thread_pool () = default;
182
0981fe10 183#if CXX_STD_THREAD
a0b57563
CB
184 /* The callback for each worker thread. */
185 void thread_function ();
186
f4565e4c
TT
187 /* Post a task to the thread pool. A future is returned, which can
188 be used to wait for the result. */
189 void do_post_task (std::packaged_task<void ()> &&func);
190
a0b57563
CB
191 /* The current thread count. */
192 size_t m_thread_count = 0;
193
194 /* A convenience typedef for the type of a task. */
11d7dd33 195 typedef std::packaged_task<void ()> task_t;
a0b57563
CB
196
197 /* The tasks that have not been processed yet. An optional is used
198 to represent a task. If the optional is empty, then this means
199 that the receiving thread should terminate. If the optional is
200 non-empty, then it is an actual task to evaluate. */
6b09f134 201 std::queue<std::optional<task_t>> m_tasks;
a0b57563
CB
202
203 /* A condition variable and mutex that are used for communication
204 between the main thread and the worker threads. */
205 std::condition_variable m_tasks_cv;
206 std::mutex m_tasks_mutex;
33ae4543 207 bool m_sized_at_least_once = false;
0981fe10 208#endif /* CXX_STD_THREAD */
a0b57563
CB
209};
210
211}
212
213#endif /* GDBSUPPORT_THREAD_POOL_H */