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