MySQL 8.0.31
Source Code Documentation
os0once.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2014, 2022, 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 also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25*****************************************************************************/
26
27/** @file include/os0once.h
28 A class that aids executing a given function exactly once in a multi-threaded
29 environment.
30
31 Created Feb 20, 2014 Vasil Dimov
32 *******************************************************/
33
34#ifndef os0once_h
35#define os0once_h
36
37#include "univ.i"
38
39#include "os0atomic.h"
40#include "ut0ut.h"
41
42/** Execute a given function exactly once in a multi-threaded environment
43or wait for the function to be executed by another thread.
44
45Example usage:
46First the user must create a control variable of type os_once::state_t and
47assign it os_once::NEVER_DONE.
48Then the user must pass this variable, together with a function to be
49executed to os_once::do_or_wait_for_done().
50
51Multiple threads can call os_once::do_or_wait_for_done() simultaneously with
52the same (os_once::state_t) control variable. The provided function will be
53called exactly once and when os_once::do_or_wait_for_done() returns then this
54function has completed execution, by this or another thread. In other words
55os_once::do_or_wait_for_done() will either execute the provided function or
56will wait for its execution to complete if it is already called by another
57thread or will do nothing if the function has already completed its execution
58earlier.
59
60This mimics pthread_once(3), but unfortunately pthread_once(3) does not
61support passing arguments to the init_routine() function. We should use
62std::call_once() when we start compiling with C++11 enabled. */
63class os_once {
64 public:
65 /** Control variables' state type */
66 typedef uint32_t state_t;
67
68 /** Not yet executed. */
69 static const state_t NEVER_DONE = 0;
70
71 /** Currently being executed by this or another thread. */
72 static const state_t IN_PROGRESS = 1;
73
74 /** Finished execution. */
75 static const state_t DONE = 2;
76
77 /** Call a given function or wait its execution to complete if it is
78 already called by another thread.
79 @param[in,out] state control variable
80 @param[in] do_func function to call
81 @param[in,out] do_func_arg an argument to pass to do_func(). */
82 static void do_or_wait_for_done(std::atomic<state_t> *state,
83 void (*do_func)(void *), void *do_func_arg) {
84 /* Avoid calling compare_exchange_strong() in the most common case. */
85 if (*state == DONE) {
86 return;
87 }
88
89 state_t never_done = NEVER_DONE;
90 if (state->compare_exchange_strong(never_done, IN_PROGRESS)) {
91 /* We are the first. Call the function. */
92
93 do_func(do_func_arg);
94
96 const bool swapped = state->compare_exchange_strong(in_progress, DONE);
97
98 ut_a(swapped);
99 } else {
100 /* The state is not NEVER_DONE, so either it is
101 IN_PROGRESS (somebody is calling the function right
102 now or DONE (it has already been called and completed).
103 Wait for it to become DONE. */
104 for (;;) {
105 const state_t s = *state;
106
107 switch (s) {
108 case DONE:
109 return;
110 case IN_PROGRESS:
111 break;
112 case NEVER_DONE:
113 [[fallthrough]];
114 default:
115 ut_error;
116 }
117
118#ifndef UNIV_HOTBACKUP
119 UT_RELAX_CPU();
120#endif /* !UNIV_HOTBACKUP */
121 }
122 }
123 }
124};
125
126#endif /* os0once_h */
Execute a given function exactly once in a multi-threaded environment or wait for the function to be ...
Definition: os0once.h:63
static void do_or_wait_for_done(std::atomic< state_t > *state, void(*do_func)(void *), void *do_func_arg)
Call a given function or wait its execution to complete if it is already called by another thread.
Definition: os0once.h:82
static const state_t NEVER_DONE
Not yet executed.
Definition: os0once.h:69
static const state_t DONE
Finished execution.
Definition: os0once.h:75
static const state_t IN_PROGRESS
Currently being executed by this or another thread.
Definition: os0once.h:72
uint32_t state_t
Control variables' state type.
Definition: os0once.h:66
bool in_progress()
Check if upgrade is in progress.
Definition: upgrade.cc:113
Macros for using atomics.
Version control for database, common definitions, and include files.
#define ut_error
Abort execution.
Definition: ut0dbg.h:64
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:56
Various utilities.
#define UT_RELAX_CPU()
Definition: ut0ut.h:86