MySQL 8.0.42
Source Code Documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
lock_free_type.h
Go to the documentation of this file.
1/* Copyright (c) 2020, 2025, Oracle and/or its affiliates.
2
3This program is free software; you can redistribute it and/or modify it under
4the terms of the GNU General Public License, version 2.0, as published by the
5Free Software Foundation.
6
7This program is designed to work with certain software (including
8but not limited to OpenSSL) that is licensed under separate terms,
9as designated in a particular file or component or in included license
10documentation. The authors of MySQL hereby grant you an additional
11permission to link the program and your derivative works with the
12separately licensed software that they have either included with
13the program or referenced in the documentation.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
18for more details.
19
20You should have received a copy of the GNU General Public License along with
21this program; if not, write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24/** @file storage/temptable/include/temptable/lock_free_type.h
25Lock-free type (selection) implementation. */
26
27#ifndef TEMPTABLE_LOCK_FREE_TYPE_H
28#define TEMPTABLE_LOCK_FREE_TYPE_H
29
30#include <atomic>
31#include <type_traits>
32
33#include "my_config.h"
35
36namespace temptable {
37
38/** Clang has a bug which causes ATOMIC_LLONG_LOCK_FREE to be defined as 1
39 * (or "sometimes lock-free") in 32-bit builds even though
40 * __atomic_always_lock_free returns true for the same type on the same
41 * platform. This is an inconsistency which can be easily verified by:
42 *
43 * % clang -dM -E -x c /dev/null | grep LLONG_LOCK
44 * #define __CLANG_ATOMIC_LLONG_LOCK_FREE 2
45 * #define __GCC_ATOMIC_LLONG_LOCK_FREE 2
46 *
47 * % clang -m32 -dM -E -x c /dev/null | grep LLONG_LOCK
48 * #define __CLANG_ATOMIC_LLONG_LOCK_FREE 1
49 * #define __GCC_ATOMIC_LLONG_LOCK_FREE 1
50 *
51 * % gcc -dM -E -x c /dev/null | grep LLONG_LOCK
52 * #define __GCC_ATOMIC_LLONG_LOCK_FREE 2
53 *
54 * % gcc -m32 -dM -E -x c /dev/null | grep LLONG_LOCK
55 * #define __GCC_ATOMIC_LLONG_LOCK_FREE 2
56 *
57 * There has been some work towards fixing this issue:
58 * * https://bugs.llvm.org/show_bug.cgi?id=30581
59 * * Introduces the fix for the aforementioned problem but ...
60 * * https://bugs.llvm.org/show_bug.cgi?id=31864
61 * * ... reverts the fix because it breaks some other targets, e.g.
62 * 32-bit FreeBSD
63 *
64 * Some more links:
65 * * https://reviews.llvm.org/D28213
66 * * https://reviews.llvm.org/D29542
67 */
68#if defined(__clang__) && (SIZEOF_VOIDP == 4) && (ATOMIC_LLONG_LOCK_FREE == 1)
69#define WORKAROUND_PR31864_CLANG_BUG (1)
70#else
71#define WORKAROUND_PR31864_CLANG_BUG (0)
72#endif
73
74/** Enum class describing alignment-requirements. */
76
77/** Lock-free type selector, a helper utility which evaluates during
78 * the compile-time whether the given type T has a property of being
79 * always-lock-free for given platform. If true, Lock_free_type_selector::Type
80 * will hold T, otherwise Lock_free_type_selector::Type will be inexisting in
81 * which case static-assert will be triggered with a hopefully descriptive
82 * error-message. In the event of static-assert, one can either try to select
83 * another type T or, if one does not care about the actual underlying
84 * type representation, simply utilize the `Largest_lock_free_type_selector`
85 * utility instead. This utility will work out those details automagically. For
86 * more information, see documentation on `Largest_lock_free_type_selector`.
87 *
88 * In short, reasoning behind this machinery lies in the fact that the standard
89 * cannot guarantee that underlying implementation of std::atomic<T> is going
90 * to be able to use lock-free atomic CPU instructions. That obviously depends
91 * on the given type T but also on the properties of concrete platform.
92 * Therefore, actual implementation is mostly platform-dependent and is
93 * free to choose any other locking operation (e.g. mutex) as long as it is
94 * able to fulfill the atomicity. Lock-freedom is not a pre-requisite. Only
95 * exception is std::atomic_flag.
96 *
97 * For certain types, however, lock-freedom can be claimed upfront during the
98 * compile-time phase, and this is where this utiliy kicks in. It is essentially
99 * a C++14 rewrite of std::atomic<T>::is_always_lock_free which is only
100 * available from C++17 onwards. Once moved to C++17 this utility will become
101 * obsolete and shall be replaced with standard-compliant implementation.
102 *
103 * More details and motivation can be found at:
104 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0152r0.html
105 * */
106template <typename T, typename V = void>
108 static_assert(
109 !std::is_same<T, T>::value,
110 "No always-lock-free property could be found for given type. "
111 "Type provided is probably not a built-in (fundamental) type or a "
112 "pointer which makes it impossible for this particular check to be "
113 "excercised at compile-time.");
114};
115
116/** Template-specialization for trivially-copyable classes/structs.
117 *
118 * Subset of trivially-copyable classes/structs might have always-lock-free
119 * property but for this feature to be implemented we would have to go at great
120 * lengths to implement cross-platform support. Therefore, for simplicity
121 * reasons let's just detect the overload and fail gracefully.
122 * */
123template <typename T>
125 T, typename std::enable_if<std::is_class<T>::value and
126 std::is_trivially_copyable<T>::value>::type> {
127 static_assert(!std::is_same<T, T>::value,
128 "Querying always-lock-free property of trivially-copyable "
129 "classes or structs is not yet implemented!");
130};
131
132/** Template-specialization for pointer types. */
133template <typename T>
135 T, typename std::enable_if<std::is_pointer<T>::value>::type> {
136#if (ATOMIC_POINTER_LOCK_FREE == 2)
137 using Type = T;
138#else
139 static_assert(false,
140 "Pointer type on this platform does not have an "
141 "always-lock-free property. Bailing out ...");
142#endif
143};
144
145/** Template-specialization for long long types. */
146template <typename T>
148 T,
149 typename std::enable_if<std::is_same<T, long long>::value or
150 std::is_same<T, unsigned long long>::value>::type> {
151#if (ATOMIC_LLONG_LOCK_FREE == 2) || (WORKAROUND_PR31864_CLANG_BUG == 1)
152 using Type = T;
153#else
154 static_assert(false,
155 "(unsigned) long long type on this platform does not have an "
156 "always-lock-free property. Bailing out ...");
157#endif
158};
159
160/** Template-specialization for long types. */
161template <typename T>
163 T, typename std::enable_if<std::is_same<T, long>::value or
164 std::is_same<T, unsigned long>::value>::type> {
165#if (ATOMIC_LONG_LOCK_FREE == 2)
166 using Type = T;
167#else
168 static_assert(false,
169 "(unsigned) long type on this platform does not have an "
170 "always-lock-free property. Bailing out ...");
171#endif
172};
173
174/** Template-specialization for int types. */
175template <typename T>
177 T, typename std::enable_if<std::is_same<T, int>::value or
178 std::is_same<T, unsigned int>::value>::type> {
179#if (ATOMIC_INT_LOCK_FREE == 2)
180 using Type = T;
181#else
182 static_assert(false,
183 "(unsigned) int type on this platform does not have an "
184 "always-lock-free property. Bailing out ...");
185#endif
186};
187
188/** Template-specialization for short types. */
189template <typename T>
191 T, typename std::enable_if<std::is_same<T, short>::value or
192 std::is_same<T, unsigned short>::value>::type> {
193#if (ATOMIC_SHORT_LOCK_FREE == 2)
194 using Type = T;
195#else
196 static_assert(false,
197 "(unsigned) short type on this platform does not have an "
198 "always-lock-free property. Bailing out ...");
199#endif
200};
201
202/** Template-specialization for char types. */
203template <typename T>
205 T, typename std::enable_if<std::is_same<T, char>::value or
206 std::is_same<T, unsigned char>::value>::type> {
207#if (ATOMIC_CHAR_LOCK_FREE == 2)
208 using Type = T;
209#else
210 static_assert(false,
211 "(unsigned) char type on this platform does not have an "
212 "always-lock-free property. Bailing out ...");
213#endif
214};
215
216/** Template-specialization for boolean types. */
217template <typename T>
219 T, typename std::enable_if<std::is_same<T, bool>::value>::type> {
220#if (ATOMIC_BOOL_LOCK_FREE == 2)
221 using Type = T;
222#else
223 static_assert(false,
224 "bool type on this platform does not have an "
225 "always-lock-free property. Bailing out ...");
226#endif
227};
228
229/** Largest lock-free type selector, a helper utility very much similar
230 * to Lock_free_type_selector with the difference being that it tries hard
231 * not to fail. E.g. it will try to find the largest available T for given
232 * platform which has a property of being always-lock-free. T which has been
233 * selected is then found in Largest_lock_free_type_selector::Type.
234 * Signedness of T is respected.
235 * */
236template <typename T, typename V = void>
238 static_assert(
239 !std::is_same<T, T>::value,
240 "No always-lock-free property could be found for given type. "
241 "Type provided is probably not a built-in (fundamental) type or a "
242 "pointer which makes it impossible for this particular check to be "
243 "excercised at compile-time.");
244};
245
246/** Template-specialization for pointer types. */
247template <typename T>
249 T, typename std::enable_if<std::is_pointer<T>::value>::type> {
250#if (ATOMIC_POINTER_LOCK_FREE == 2)
251 using Type = T;
252#else
253 static_assert(false,
254 "Pointer type on this platform does not have an "
255 "always-lock-free property. Bailing out ...");
256#endif
257};
258
259/** Template-specialization for integral types. */
260template <typename T>
262 T, typename std::enable_if<std::is_integral<T>::value>::type> {
263#if (ATOMIC_LLONG_LOCK_FREE == 2) || (WORKAROUND_PR31864_CLANG_BUG == 1)
264 using Type = std::conditional_t<std::is_unsigned<T>::value,
265 unsigned long long, long long>;
266#elif (ATOMIC_LONG_LOCK_FREE == 2)
267 using Type =
268 std::conditional_t<std::is_unsigned<T>::value, unsigned long, long>;
269#elif (ATOMIC_INT_LOCK_FREE == 2)
270 using Type =
271 std::conditional_t<std::is_unsigned<T>::value, unsigned int, int>;
272#elif (ATOMIC_SHORT_LOCK_FREE == 2)
273 using Type =
274 std::conditional_t<std::is_unsigned<T>::value, unsigned short, short>;
275#elif (ATOMIC_CHAR_LOCK_FREE == 2)
276 using Type =
277 std::conditional_t<std::is_unsigned<T>::value, unsigned char, char>;
278#elif (ATOMIC_BOOL_LOCK_FREE == 2)
279 using Type = bool;
280#else
281 static_assert(
282 false,
283 "No suitable always-lock-free type was found for this platform. "
284 "Bailing out ...");
285#endif
286};
287
288/** Representation of an atomic type which is guaranteed to be always-lock-free.
289 * In case always-lock-free property cannot be satisfied for given T,
290 * Lock_free_type instantiation will fail with the compile-time error.
291 *
292 * Always-lock-free guarantee is implemented through the means of
293 * Lock_free_type_selector or Largest_lock_free_type_selector. User code can
294 * opt-in for any of those. By default, Lock_free_type_selector is used.
295 *
296 * In addition, this type provides an ability to redefine the
297 * alignment-requirement of the underlying always-lock-free type, basically
298 * making it possible to over-align T to the size of the L1-data cache-line
299 * size. By default, T has a natural alignment.
300 */
301template <typename T, Alignment ALIGN = Alignment::NATURAL,
302 template <typename, typename = void> class TypeSelector =
305 using Type = typename TypeSelector<T>::Type;
306 std::atomic<Type> m_value;
307};
308
309/*
310 * Template-specialization for Lock_free_type with alignment-requirement set to
311 * L1-data cache size.
312 * */
313template <typename T, template <typename, typename = void> class TypeSelector>
314struct Lock_free_type<T, Alignment::L1_DCACHE_SIZE, TypeSelector> {
315 using Type = typename TypeSelector<T>::Type;
316 alignas(L1_DCACHE_SIZE) std::atomic<Type> m_value;
317};
318
319} // namespace temptable
320
321#endif /* TEMPTABLE_LOCK_FREE_TYPE_H */
Type
Definition: resource_group_basic_types.h:33
Definition: gcs_xcom_synode.h:64
Definition: allocator.h:45
Alignment
Enum class describing alignment-requirements.
Definition: lock_free_type.h:75
constexpr size_t L1_DCACHE_SIZE
Store L1-dcache size information into the constexpr expression.
Definition: constants.h:82
required string type
Definition: replication_group_member_actions.proto:34
TempTable constants.
Largest lock-free type selector, a helper utility very much similar to Lock_free_type_selector with t...
Definition: lock_free_type.h:237
typename TypeSelector< T >::Type Type
Definition: lock_free_type.h:315
Lock-free type selector, a helper utility which evaluates during the compile-time whether the given t...
Definition: lock_free_type.h:107
Representation of an atomic type which is guaranteed to be always-lock-free.
Definition: lock_free_type.h:304
typename TypeSelector< T >::Type Type
Definition: lock_free_type.h:305
std::atomic< Type > m_value
Definition: lock_free_type.h:306