MySQL 26.10.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"
42#include "sql/sql_class.h"
44#include "sync0debug.h"
45#include "ut0log.h" /* ib::warn */
46
47#include <atomic>
48#include <functional>
49
50#ifdef HAVE_ASAN
51#include <sanitizer/asan_interface.h>
52#endif
53
54/** Maximum number of threads inside InnoDB */
55extern uint32_t srv_max_n_threads;
56
57/** Number of threads active. */
58extern std::atomic_int os_thread_count;
59
60/** Initializes OS thread management data structures. */
61inline void os_thread_open() { /* No op */
62}
63
64/** Check if there are threads active.
65@return true if the thread count > 0. */
66inline bool os_thread_any_active() {
67 return os_thread_count.load(std::memory_order_relaxed) > 0;
68}
69
70/** Frees OS thread management data structures. */
71inline void os_thread_close() {
73 ib::warn(ER_IB_MSG_1274, os_thread_count.load(std::memory_order_relaxed));
74 }
75}
76
77/** Register with MySQL infrastructure. */
79 public:
80#ifdef UNIV_PFS_THREAD
81 /** Constructor for the Runnable object.
82 @param[in] pfs_key Performance schema key
83 @param[in] pfs_seqnum Performance schema sequence number */
84 explicit MySQL_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
85 : m_pfs_key(pfs_key), m_pfs_seqnum(pfs_seqnum) {}
86#else
87 /** Constructor for the Runnable object.
88 @param[in] pfs_key Performance schema key (ignored)
89 @param[in] pfs_seqnum Performance schema sequence number */
91#endif /* UNIV_PFS_THREAD */
92
93 protected:
94 /** Register the thread with the server */
95 void preamble() {
96 const bool ret = my_thread_init();
97 ut_a(!ret);
98
99#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
101 auto &value = m_pfs_key.m_value;
102 auto psi = PSI_THREAD_CALL(new_thread)(value, m_pfs_seqnum, this, 0);
103
104 PSI_THREAD_CALL(set_thread_os_id)(psi);
105 PSI_THREAD_CALL(set_thread)(psi);
106 }
107#endif /* UNIV_PFS_THREAD && !UNIV_HOTBACKUP */
108 }
109
110 /** Deregister the thread */
111 void epilogue() {
113
114#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
116 PSI_THREAD_CALL(delete_current_thread)();
117 }
118#endif /* UNIV_PFS_THREAD && !UNIV_HOTBACKUP */
119 }
120
121 /** @return a THD instance. */
123#ifdef UNIV_PFS_THREAD
124 return create_thd(false, true, true, m_pfs_key.m_value, m_pfs_seqnum);
125#else
126 return create_thd(false, true, true, 0, 0);
127#endif /* UNIV_PFS_THREAD */
128 }
129
130 /** Destroy a THD instance.
131 @param[in,out] thd Instance to destroy. */
132 void destroy_mysql_thd(THD *thd) noexcept { destroy_thd(thd); }
133
134 protected:
135#ifdef UNIV_PFS_THREAD
136 /** Performance schema key */
138
139 /** Performance schema sequence number */
141#endif /* UNIV_PFS_THREAD */
142};
143
144/** Execute in the context of a non detached MySQL thread. */
145class Runnable : public MySQL_thread {
146 public:
147 /** Constructor for the Runnable object.
148 @param[in] pfs_key Performance schema key
149 @param[in] pfs_seqnum Performance schema sequence number */
150 explicit Runnable(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
151 : MySQL_thread(pfs_key, pfs_seqnum) {
153 }
154
155 /** Create and configure the current THD for this Runnable.
156 @param[in] caller_thd Source session context to copy, or nullptr. */
157 dberr_t setup_thd(const THD *caller_thd = nullptr) noexcept {
158 ut_ad(m_thd == nullptr);
159
160 m_thd = create_current_thd(caller_thd);
161 return m_thd == nullptr ? DB_OUT_OF_MEMORY : DB_SUCCESS;
162 }
163
164 /** Destroy the current THD and deregister the MySQL thread. */
166 if (m_thd != nullptr) {
168 }
169
171 }
172
173 /** Method to execute the callable
174 @param[in] f Callable object
175 @param[in] args Variable number of args to F
176 @retval f return value. */
177 template <typename F, typename... Args>
178 dberr_t operator()(F &&f, Args &&...args) {
179 return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
180 }
181
182 private:
183 /** Create and configure the THD used by this DDL worker invocation. */
184 THD *create_current_thd(const THD *caller_thd) noexcept {
185 ut_ad(current_thd == nullptr);
186
187 auto thd = create_mysql_thd();
188 if (thd == nullptr) {
189 return nullptr;
190 }
191
192 ut_ad_eq(current_thd, thd);
193
194 if (caller_thd != nullptr) {
195#ifdef HAVE_ASAN
196 ASAN_POISON_MEMORY_REGION((void *)&thd->variables,
197 sizeof(thd->variables));
198 ASAN_UNPOISON_MEMORY_REGION((void *)&thd->variables.sql_mode,
199 sizeof(thd->variables.sql_mode));
200#endif
201 thd->variables.sql_mode = caller_thd->variables.sql_mode;
202 ut_d(Sync_point::clone_from(caller_thd);)
203 }
204
205 return thd;
206 }
207
208 /** Destroy a THD created by create_current_thd(). */
209 void destroy_current_thd(THD *thd) noexcept {
210 ut_ad_eq(current_thd, thd);
211
212#ifdef HAVE_ASAN
213 ASAN_UNPOISON_MEMORY_REGION((void *)&thd->variables,
214 sizeof(thd->variables));
215#endif
218
219 ut_ad(current_thd == nullptr);
220 }
221
222 THD *m_thd{nullptr};
223};
224
225/** Wrapper for a callable, it will count the number of registered
226Runnable instances and will register the thread executing the callable
227with the PFS and the Server threading infrastructure. */
229 public:
230 /** Constructor for the detached thread.
231 @param[in] pfs_key Performance schema key
232 @param[in] pfs_seqnum Performance schema sequence number */
234 PSI_thread_seqnum pfs_seqnum)
235 : MySQL_thread(pfs_key, pfs_seqnum) {
236 init();
237 }
238
239 /** Method to execute the callable
240 @param[in] f Callable object
241 @param[in] args Variable number of args to F */
242 template <typename F, typename... Args>
243 void operator()(F &&f, Args &&...args) {
245 UT_RELAX_CPU();
246 }
247
249
250 preamble();
251
253
254 std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
255
256 epilogue();
257
259 }
260
261 /** @return thread handle. */
262 IB_thread thread() const { return (m_thread); }
263
264 private:
265 /** Initializes the m_shared_future, uses the m_promise's get_future,
266 which cannot be used since then, according to its documentation. */
268
269 /** Register the thread with the server */
270 void preamble() {
272
273 std::atomic_thread_fence(std::memory_order_release);
274
275 auto old = os_thread_count.fetch_add(1, std::memory_order_relaxed);
276
277 ut_a(old <= static_cast<int>(srv_max_n_threads) - 1);
278 }
279
280 /** Deregister the thread */
281 void epilogue() {
282 m_promise.set_value();
283
284 std::atomic_thread_fence(std::memory_order_release);
285
286 auto old = os_thread_count.fetch_sub(1, std::memory_order_relaxed);
287
288 ut_a(old > 0);
289
291 }
292
293 private:
294 /** Future object which keeps the ref counter >= 1 at least
295 as long as the Detached_thread is not-destroyed. */
297
298 /** Promise which is set when task is done. */
299 std::promise<void> m_promise;
300};
301
302/** Check if thread is stopped
303@param[in] thread Thread handle.
304@return true if the thread has started, finished tasks and stopped. */
305inline bool thread_is_stopped(const IB_thread &thread) {
306 return thread.state() == IB_thread::State::STOPPED;
307}
308
309/** Check if thread is active
310@param[in] thread Thread handle.
311@return true if the thread is active. */
312inline bool thread_is_active(const IB_thread &thread) {
313 switch (thread.state()) {
315 /* Not yet started. */
316 return false;
317
319 /* Thread "thread" is already active, but start() has not been called.
320 Note that when start() is called, the thread's routine may decide to
321 check if it is active or trigger other thread to do similar check
322 regarding "thread". That could happen faster than thread's state
323 is advanced from ALLOWED_TO_START to STARTED. Therefore we must
324 already consider such thread as "active". */
325 return true;
326
328 /* Note, that potentially the thread might be doing its cleanup after
329 it has already ended its task. We still consider it active, until the
330 cleanup is finished. */
331 return true;
332
334 /* Ended its task and became marked as STOPPED (cleanup finished) */
335 return false;
336
338 default:
339 /* The thread object has not been assigned yet. */
340 return false;
341 }
342
343 /* Note that similar goal was achieved by the usage of shared_future:
344 return (shared_future.valid() && shared_future.wait_for(std::chrono::seconds(
345 0)) != std::future_status::ready);
346 However this resulted in longer execution of mtr tests (63minutes ->
347 75minutes). You could try `mtr --mem collations.esperanto` (cmake
348 WITH_DEBUG=1) */
349}
350
351/** Create a detached non-started thread. After thread is created, you should
352assign the received object to any of variables/fields which you later could
353access to check thread's state. You are allowed to either move or copy that
354object (any number of copies is allowed). After assigning you are allowed to
355start the thread by calling start() on any of those objects.
356@param[in] pfs_key Performance schema thread key
357@param[in] pfs_seqnum Performance schema thread sequence number
358@param[in] f Callable instance
359@param[in] args Zero or more args
360@return Object which allows to start the created thread, monitor its state and
361 wait until the thread is finished. */
362template <typename F, typename... Args>
364 PSI_thread_seqnum pfs_seqnum, F &&f,
365 Args &&...args) {
366 Detached_thread detached_thread{pfs_key, pfs_seqnum};
367 auto thread = detached_thread.thread();
368
369 std::thread t(std::move(detached_thread), f, args...);
370 t.detach();
371
372 /* Thread t is doing busy waiting until the state is changed
373 from NOT_STARTED to ALLOWED_TO_START. That will happen when
374 thread.start() will be called. */
375 ut_a(thread.state() == IB_thread::State::NOT_STARTED);
376
377 return thread;
378}
379
380#ifdef UNIV_PFS_THREAD
381#define os_thread_create(...) create_detached_thread(__VA_ARGS__)
382#else
383#define os_thread_create(k, s, ...) create_detached_thread(0, 0, __VA_ARGS__)
384#endif /* UNIV_PFS_THREAD */
385
386/** Parallel for loop over a container.
387@param[in] pfs_key Performance schema thread key
388@param[in] c Container to iterate over in parallel
389@param[in] n Number of threads to create
390@param[in] f Callable instance
391@param[in] args Zero or more args */
392template <typename Container, typename F, typename... Args>
393void par_for(mysql_pfs_key_t pfs_key, const Container &c, size_t n, F &&f,
394 Args &&...args) {
395 if (c.empty()) {
396 return;
397 }
398
399 size_t slice = (n > 0) ? c.size() / n : 0;
400
401 using Workers = std::vector<IB_thread>;
402
403 Workers workers;
404
405 workers.reserve(n);
406
407 for (size_t i = 0; i < n; ++i) {
408 auto b = c.begin() + (i * slice);
409 auto e = b + slice;
410
411 auto worker = os_thread_create(pfs_key, i, f, b, e, i, args...);
412 worker.start();
413
414 workers.push_back(std::move(worker));
415 }
416
417 f(c.begin() + (n * slice), c.end(), n, args...);
418
419 for (auto &worker : workers) {
420 worker.join();
421 }
422}
423
424#if defined(UNIV_PFS_THREAD) && !defined(UNIV_HOTBACKUP)
425#define par_for(...) par_for(__VA_ARGS__)
426#else
427#define par_for(k, ...) par_for(0, __VA_ARGS__)
428#endif /* UNIV_PFS_THREAD */
429
430#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:228
void operator()(F &&f, Args &&...args)
Method to execute the callable.
Definition: os0thread-create.h:243
void init()
Initializes the m_shared_future, uses the m_promise's get_future, which cannot be used since then,...
Definition: os0thread-create.h:267
std::promise< void > m_promise
Promise which is set when task is done.
Definition: os0thread-create.h:299
Detached_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the detached thread.
Definition: os0thread-create.h:233
void preamble()
Register the thread with the server.
Definition: os0thread-create.h:270
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:296
IB_thread thread() const
Definition: os0thread-create.h:262
void epilogue()
Deregister the thread.
Definition: os0thread-create.h:281
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:78
void epilogue()
Deregister the thread.
Definition: os0thread-create.h:111
MySQL_thread(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the Runnable object.
Definition: os0thread-create.h:84
PSI_thread_seqnum m_pfs_seqnum
Performance schema sequence number.
Definition: os0thread-create.h:140
THD * create_mysql_thd() noexcept
Definition: os0thread-create.h:122
const mysql_pfs_key_t m_pfs_key
Performance schema key.
Definition: os0thread-create.h:137
void destroy_mysql_thd(THD *thd) noexcept
Destroy a THD instance.
Definition: os0thread-create.h:132
void preamble()
Register the thread with the server.
Definition: os0thread-create.h:95
Execute in the context of a non detached MySQL thread.
Definition: os0thread-create.h:145
THD * create_current_thd(const THD *caller_thd) noexcept
Create and configure the THD used by this DDL worker invocation.
Definition: os0thread-create.h:184
~Runnable() noexcept
Destroy the current THD and deregister the MySQL thread.
Definition: os0thread-create.h:165
THD * m_thd
Definition: os0thread-create.h:222
void destroy_current_thd(THD *thd) noexcept
Destroy a THD created by create_current_thd().
Definition: os0thread-create.h:209
dberr_t operator()(F &&f, Args &&...args)
Method to execute the callable.
Definition: os0thread-create.h:178
Runnable(mysql_pfs_key_t pfs_key, PSI_thread_seqnum pfs_seqnum)
Constructor for the Runnable object.
Definition: os0thread-create.h:150
dberr_t setup_thd(const THD *caller_thd=nullptr) noexcept
Create and configure the current THD for this Runnable.
Definition: os0thread-create.h:157
static void clone_from(const THD *thd) noexcept
Clone sync points from another THD to the current THD.
Definition: sync0debug.cc:1763
static void erase(const THD *thd, const std::string &target) noexcept
Clear the named target.
Definition: sync0debug.cc:1788
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
thread_local THD * current_thd
Definition: current_thd.cc:26
dberr_t
Definition: db0err.h:39
@ DB_OUT_OF_MEMORY
Definition: db0err.h:49
@ DB_SUCCESS
Definition: db0err.h:43
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:61
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:363
#define os_thread_create(...)
Definition: os0thread-create.h:381
bool thread_is_active(const IB_thread &thread)
Check if thread is active.
Definition: os0thread-create.h:312
#define par_for(...)
Definition: os0thread-create.h:425
bool os_thread_any_active()
Check if there are threads active.
Definition: os0thread-create.h:66
void os_thread_close()
Frees OS thread management data structures.
Definition: os0thread-create.h:71
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:305
The interface to the operating system process and thread control primitives.
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
Debug checks for latches, header file.
mysql_pfs_key_t PFS_NOT_INSTRUMENTED
THD * create_thd(Channel_info *channel_info)
Definition: connection_handler_manager.cc:277
Version control for database, common definitions, and include files.
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:109
#define ut_ad_eq(LHS, RHS)
Debug-only assertion that LHS == RHS.
Definition: ut0dbg.h:119
#define ut_d(EXPR)
Debug statement.
Definition: ut0dbg.h:111
#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