MySQL 26.7.0
Source Code Documentation
os0thread-create.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1995, 2026, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/os0thread-create.h
29 The interface to the threading wrapper
30
31 Created 2016-May-17 Sunny Bains
32 *******************************************************/
33
34#ifndef os0thread_create_h
35#define os0thread_create_h
36
37#include <my_thread.h>
38
39#include "univ.i"
40
41#include "os0thread.h"
43#include "ut0log.h" /* ib::warn */
44
45#include <atomic>
46#include <functional>
47
48/** Maximum number of threads inside InnoDB */
49extern uint32_t srv_max_n_threads;
50
51/** Number of threads active. */
52extern std::atomic_int os_thread_count;
53
54/** Initializes OS thread management data structures. */
55inline void os_thread_open() { /* No op */
56}
57
58/** Check if there are threads active.
59@return true if the thread count > 0. */
60inline bool os_thread_any_active() {
61 return os_thread_count.load(std::memory_order_relaxed) > 0;
62}
63
64/** Frees OS thread management data structures. */
65inline void os_thread_close() {
67 ib::warn(ER_IB_MSG_1274, os_thread_count.load(std::memory_order_relaxed));
68 }
69}
70
71/** Register with MySQL infrastructure. */
73 public:
74#ifdef UNIV_PFS_THREAD
75 /** Constructor for the Runnable object.
76 @param[in] pfs_key Performance schema key
77 @param[in] pfs_seqnum Performance schema sequence number */
78 explicit MySQL_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
79 : m_pfs_key(pfs_key), m_pfs_seqnum(pfs_seqnum) {}
80#else
81 /** Constructor for the Runnable object.
82 @param[in] pfs_key Performance schema key (ignored)
83 @param[in] pfs_seqnum Performance schema sequence number */
85#endif /* UNIV_PFS_THREAD */
86
87 protected:
88 /** Register the thread with the server */
89 void preamble() {
90 const bool ret = my_thread_init();
91 ut_a(!ret);
92
93#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
95 auto &value = m_pfs_key.m_value;
96 auto psi = PSI_THREAD_CALL(new_thread)(value, m_pfs_seqnum, this, 0);
97
98 PSI_THREAD_CALL(set_thread_os_id)(psi);
99 PSI_THREAD_CALL(set_thread)(psi);
100 }
101#endif /* UNIV_PFS_THREAD && !UNIV_HOTBACKUP */
102 }
103
104 /** Deregister the thread */
105 void epilogue() {
107
108#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
110 PSI_THREAD_CALL(delete_current_thread)();
111 }
112#endif /* UNIV_PFS_THREAD && !UNIV_HOTBACKUP */
113 }
114
115 /** @return a THD instance. */
117#ifdef UNIV_PFS_THREAD
118 return create_thd(false, true, true, m_pfs_key.m_value, m_pfs_seqnum);
119#else
120 return create_thd(false, true, true, 0, 0);
121#endif /* UNIV_PFS_THREAD */
122 }
123
124 /** Destroy a THD instance.
125 @param[in,out] thd Instance to destroy. */
126 void destroy_mysql_thd(THD *thd) noexcept { destroy_thd(thd); }
127
128 protected:
129#ifdef UNIV_PFS_THREAD
130 /** Performance schema key */
132
133 /** Performance schema sequence number */
135#endif /* UNIV_PFS_THREAD */
136};
137
138/** Execute in the context of a non detached MySQL thread. */
139class Runnable : public MySQL_thread {
140 public:
141 /** Constructor for the Runnable object.
142 @param[in] pfs_key Performance schema key
143 @param[in] pfs_seqnum Performance schema sequence number */
144 explicit Runnable(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
145 : MySQL_thread(pfs_key, pfs_seqnum) {}
146
147 /** Method to execute the callable
148 @param[in] f Callable object
149 @param[in] args Variable number of args to F
150 @retval f return value. */
151 template <typename F, typename... Args>
152 dberr_t operator()(F &&f, Args &&...args) {
154
155 auto r = std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
156
158
159 return r;
160 }
161};
162
163/** Wrapper for a callable, it will count the number of registered
164Runnable instances and will register the thread executing the callable
165with the PFS and the Server threading infrastructure. */
167 public:
168 /** Constructor for the detached thread.
169 @param[in] pfs_key Performance schema key
170 @param[in] pfs_seqnum Performance schema sequence number */
172 PSI_thread_seqnum pfs_seqnum)
173 : MySQL_thread(pfs_key, pfs_seqnum) {
174 init();
175 }
176
177 /** Method to execute the callable
178 @param[in] f Callable object
179 @param[in] args Variable number of args to F */
180 template <typename F, typename... Args>
181 void operator()(F &&f, Args &&...args) {
183 UT_RELAX_CPU();
184 }
185
187
188 preamble();
189
191
192 std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
193
194 epilogue();
195
197 }
198
199 /** @return thread handle. */
200 IB_thread thread() const { return (m_thread); }
201
202 private:
203 /** Initializes the m_shared_future, uses the m_promise's get_future,
204 which cannot be used since then, according to its documentation. */
206
207 /** Register the thread with the server */
208 void preamble() {
210
211 std::atomic_thread_fence(std::memory_order_release);
212
213 auto old = os_thread_count.fetch_add(1, std::memory_order_relaxed);
214
215 ut_a(old <= static_cast<int>(srv_max_n_threads) - 1);
216 }
217
218 /** Deregister the thread */
219 void epilogue() {
220 m_promise.set_value();
221
222 std::atomic_thread_fence(std::memory_order_release);
223
224 auto old = os_thread_count.fetch_sub(1, std::memory_order_relaxed);
225
226 ut_a(old > 0);
227
229 }
230
231 private:
232 /** Future object which keeps the ref counter >= 1 at least
233 as long as the Detached_thread is not-destroyed. */
235
236 /** Promise which is set when task is done. */
237 std::promise<void> m_promise;
238};
239
240/** Check if thread is stopped
241@param[in] thread Thread handle.
242@return true if the thread has started, finished tasks and stopped. */
243inline bool thread_is_stopped(const IB_thread &thread) {
244 return thread.state() == IB_thread::State::STOPPED;
245}
246
247/** Check if thread is active
248@param[in] thread Thread handle.
249@return true if the thread is active. */
250inline bool thread_is_active(const IB_thread &thread) {
251 switch (thread.state()) {
253 /* Not yet started. */
254 return false;
255
257 /* Thread "thread" is already active, but start() has not been called.
258 Note that when start() is called, the thread's routine may decide to
259 check if it is active or trigger other thread to do similar check
260 regarding "thread". That could happen faster than thread's state
261 is advanced from ALLOWED_TO_START to STARTED. Therefore we must
262 already consider such thread as "active". */
263 return true;
264
266 /* Note, that potentially the thread might be doing its cleanup after
267 it has already ended its task. We still consider it active, until the
268 cleanup is finished. */
269 return true;
270
272 /* Ended its task and became marked as STOPPED (cleanup finished) */
273 return false;
274
276 default:
277 /* The thread object has not been assigned yet. */
278 return false;
279 }
280
281 /* Note that similar goal was achieved by the usage of shared_future:
282 return (shared_future.valid() && shared_future.wait_for(std::chrono::seconds(
283 0)) != std::future_status::ready);
284 However this resulted in longer execution of mtr tests (63minutes ->
285 75minutes). You could try `mtr --mem collations.esperanto` (cmake
286 WITH_DEBUG=1) */
287}
288
289/** Create a detached non-started thread. After thread is created, you should
290assign the received object to any of variables/fields which you later could
291access to check thread's state. You are allowed to either move or copy that
292object (any number of copies is allowed). After assigning you are allowed to
293start the thread by calling start() on any of those objects.
294@param[in] pfs_key Performance schema thread key
295@param[in] pfs_seqnum Performance schema thread sequence number
296@param[in] f Callable instance
297@param[in] args Zero or more args
298@return Object which allows to start the created thread, monitor its state and
299 wait until the thread is finished. */
300template <typename F, typename... Args>
302 PSI_thread_seqnum pfs_seqnum, F &&f,
303 Args &&...args) {
304 Detached_thread detached_thread{pfs_key, pfs_seqnum};
305 auto thread = detached_thread.thread();
306
307 std::thread t(std::move(detached_thread), f, args...);
308 t.detach();
309
310 /* Thread t is doing busy waiting until the state is changed
311 from NOT_STARTED to ALLOWED_TO_START. That will happen when
312 thread.start() will be called. */
313 ut_a(thread.state() == IB_thread::State::NOT_STARTED);
314
315 return thread;
316}
317
318#ifdef UNIV_PFS_THREAD
319#define os_thread_create(...) create_detached_thread(__VA_ARGS__)
320#else
321#define os_thread_create(k, s, ...) create_detached_thread(0, 0, __VA_ARGS__)
322#endif /* UNIV_PFS_THREAD */
323
324/** Parallel for loop over a container.
325@param[in] pfs_key Performance schema thread key
326@param[in] c Container to iterate over in parallel
327@param[in] n Number of threads to create
328@param[in] f Callable instance
329@param[in] args Zero or more args */
330template <typename Container, typename F, typename... Args>
331void par_for(mysql_pfs_key_t pfs_key, const Container &c, size_t n, F &&f,
332 Args &&...args) {
333 if (c.empty()) {
334 return;
335 }
336
337 size_t slice = (n > 0) ? c.size() / n : 0;
338
339 using Workers = std::vector<IB_thread>;
340
341 Workers workers;
342
343 workers.reserve(n);
344
345 for (size_t i = 0; i < n; ++i) {
346 auto b = c.begin() + (i * slice);
347 auto e = b + slice;
348
349 auto worker = os_thread_create(pfs_key, i, f, b, e, i, args...);
350 worker.start();
351
352 workers.push_back(std::move(worker));
353 }
354
355 f(c.begin() + (n * slice), c.end(), n, args...);
356
357 for (auto &worker : workers) {
358 worker.join();
359 }
360}
361
362#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
363#define par_for(...) par_for(__VA_ARGS__)
364#else
365#define par_for(k, ...) par_for(0, __VA_ARGS__)
366#endif /* UNIV_PFS_THREAD */
367
368#endif /* !os0thread_create_h */
Wrapper for a callable, it will count the number of registered Runnable instances and will register t...
Definition: os0thread-create.h:166
void operator()(F &&f, Args &&...args)
Method to execute the callable.
Definition: os0thread-create.h:181
void init()
Initializes the m_shared_future, uses the m_promise's get_future, which cannot be used since then,...
Definition: os0thread-create.h:205
std::promise< void > m_promise
Promise which is set when task is done.
Definition: os0thread-create.h:237
Detached_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the detached thread.
Definition: os0thread-create.h:171
void preamble()
Register the thread with the server.
Definition: os0thread-create.h:208
IB_thread m_thread
Future object which keeps the ref counter >= 1 at least as long as the Detached_thread is not-destroy...
Definition: os0thread-create.h:234
IB_thread thread() const
Definition: os0thread-create.h:200
void epilogue()
Deregister the thread.
Definition: os0thread-create.h:219
Definition: os0thread.h:47
void set_state(State state)
Definition: os0thread.cc:103
void init(std::promise< void > &promise)
Definition: os0thread.cc:98
State state() const
Definition: os0thread.h:51
Register with MySQL infrastructure.
Definition: os0thread-create.h:72
void epilogue()
Deregister the thread.
Definition: os0thread-create.h:105
MySQL_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the Runnable object.
Definition: os0thread-create.h:78
PSI_thread_seqnum m_pfs_seqnum
Performance schema sequence number.
Definition: os0thread-create.h:134
THD * create_mysql_thd() noexcept
Definition: os0thread-create.h:116
const mysql_pfs_key_t m_pfs_key
Performance schema key.
Definition: os0thread-create.h:131
void destroy_mysql_thd(THD *thd) noexcept
Destroy a THD instance.
Definition: os0thread-create.h:126
void preamble()
Register the thread with the server.
Definition: os0thread-create.h:89
Execute in the context of a non detached MySQL thread.
Definition: os0thread-create.h:139
dberr_t operator()(F &&f, Args &&...args)
Method to execute the callable.
Definition: os0thread-create.h:152
Runnable(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the Runnable object.
Definition: os0thread-create.h:144
For each client connection we create a separate thread with THD serving as a thread/connection descri...
Definition: sql_lexer_thd.h:36
The class warn is used to emit warnings.
Definition: ut0log.h:204
#define PSI_THREAD_CALL(M)
Definition: psi_thread.h:36
dberr_t
Definition: db0err.h:39
unsigned int PSI_thread_seqnum
Instrumented thread sequence number.
Definition: psi_thread_bits.h:59
#define F
Definition: jit_executor_value.cc:374
Defines to make different thread packages compatible.
bool my_thread_init()
Allocate thread specific memory for the thread, used by mysys and dbug.
Definition: my_thr_init.cc:264
void my_thread_end()
Deallocate memory used by the thread for book-keeping.
Definition: my_thr_init.cc:315
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
noexcept
The return type for any call_and_catch(f, args...) call where f(args...) returns Type.
Definition: call_and_catch.h:76
void os_thread_open()
Initializes OS thread management data structures.
Definition: os0thread-create.h:55
std::atomic_int os_thread_count
Number of threads active.
Definition: os0thread.cc:56
IB_thread create_detached_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum, F &&f, Args &&...args)
Create a detached non-started thread.
Definition: os0thread-create.h:301
#define os_thread_create(...)
Definition: os0thread-create.h:319
bool thread_is_active(const IB_thread &thread)
Check if thread is active.
Definition: os0thread-create.h:250
#define par_for(...)
Definition: os0thread-create.h:363
bool os_thread_any_active()
Check if there are threads active.
Definition: os0thread-create.h:60
void os_thread_close()
Frees OS thread management data structures.
Definition: os0thread-create.h:65
uint32_t srv_max_n_threads
Maximum number of threads inside InnoDB.
Definition: os0thread.cc:53
bool thread_is_stopped(const IB_thread &thread)
Check if thread is stopped.
Definition: os0thread-create.h:243
The interface to the operating system process and thread control primitives.
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
void destroy_thd(THD *thd, bool clear_pfs_events)
Cleanup the THD object, remove it from the global list of THDs and delete it.
Definition: sql_thd_internal_api.cc:169
Define for performance schema registration key.
Definition: sync0sync.h:51
unsigned int m_value
Definition: sync0sync.h:64
mysql_pfs_key_t PFS_NOT_INSTRUMENTED
THD * create_thd(Channel_info *channel_info)
Definition: connection_handler_manager.cc:271
Version control for database, common definitions, and include files.
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:97
Base of InnoDB utilities.
#define UT_RELAX_CPU()
Definition: ut0ut.h:90
int n
Definition: xcom_base.cc:509