MySQL 8.4.0
Source Code Documentation
aligned_atomic.h
Go to the documentation of this file.
1/* Copyright (c) 2008, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef MEMORY_ALIGNED_ATOMIC_H
25#define MEMORY_ALIGNED_ATOMIC_H
26
27#include <assert.h>
28#include <atomic>
29#include <cmath>
30#include <cstddef>
31#include <cstdio>
32
33#if defined(__APPLE__)
34#include <sys/sysctl.h>
35#elif defined(_WIN32)
36#include <stdlib.h>
37#include <windows.h>
38#elif defined(__linux__)
39#include <unistd.h>
40#endif
41
42#include "my_aligned_malloc.h"
43
44namespace memory {
45/**
46 Calculates and returns the size of the CPU cache line.
47
48 @return the cache line size
49 */
50#if defined(__APPLE__)
51static inline size_t _cache_line_size() {
52 size_t line_size{0};
53 size_t sizeof_line_size = sizeof(line_size);
54 sysctlbyname("hw.cachelinesize", &line_size, &sizeof_line_size, nullptr, 0);
55 return line_size;
56}
57
58#elif defined(_WIN32)
59static inline size_t _cache_line_size() {
60 size_t line_size{0};
61 DWORD buffer_size = 0;
62 DWORD i = 0;
63 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer = nullptr;
64
65 GetLogicalProcessorInformation(nullptr, &buffer_size);
66 buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(buffer_size);
67 GetLogicalProcessorInformation(&buffer[0], &buffer_size);
68
69 for (i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
70 ++i) {
71 if (buffer[i].Relationship == RelationCache && buffer[i].Cache.Level == 1) {
72 line_size = buffer[i].Cache.LineSize;
73 break;
74 }
75 }
76
77 free(buffer);
78 return line_size;
79}
80
81#elif defined(__GLIBC__)
82static inline size_t _cache_line_size() {
83 long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
84 if (size == -1) return 64;
85
86 // returns 0 on s390x RHEL 7.x and some __arch64__ configurations.
87 if (size == 0) {
88 FILE *p = fopen(
89 "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
90 if (p) {
91 if (fscanf(p, "%ld", &size) != 1) size = 0;
92 fclose(p);
93 }
94 }
95
96 if (size > 0) return static_cast<size_t>(size);
97 return 64;
98}
99
100#else
101static inline size_t _cache_line_size() { return 64; }
102#endif
103static inline size_t cache_line_size() {
104 static const size_t size{memory::_cache_line_size()};
105 return size;
106}
107
108/**
109 Retrieves the amount of bytes, multiple of the current cacheline size, needed
110 to store an element of type `T`. This is a non-caching non-thread safe helper
111 function and `memory::minimum_cacheline_for` should be used instead.
112
113 @return the amount of bytes, multiple of the current cacheline size, needed to
114 store an element of type `T`.
115 */
116template <typename T>
117static inline size_t _cacheline_for() {
118 size_t csize = memory::cache_line_size();
119 size_t size{static_cast<size_t>(std::ceil(static_cast<double>(sizeof(T)) /
120 static_cast<double>(csize))) *
121 csize};
122 return size;
123}
124
125/**
126 Retrieves the amount of bytes, multiple of the current cacheline size, needed
127 to store an element of type `T`. This function caches the computed value in a
128 static storage variable and does it in a thread-safe manner.
129
130 @return the amount of bytes, multiple of the current cacheline size, needed to
131 store an element of type `T`.
132 */
133template <typename T>
134static inline size_t minimum_cacheline_for() {
135 static const size_t size{memory::_cacheline_for<T>()};
136 return size;
137}
138
139/// @brief Template that may access Aligned_atomic internals
140template <class T>
142
143/**
144 @class memory::Aligned_atomic
145
146 Templated class that encapsulates an `std::atomic` within a byte buffer that
147 is padded to the processor cache-line size.
148
149 This class purpose is to help prevent false sharing between atomically
150 accessed variables that are contiguous in memory. This is the normal case for
151 arrays or class members declared next to each other.
152
153 If the intended usage is none of the above, `std::atomic` class should be used
154 since the below implementation allocates more memory than needed for storing
155 the intended value (in order to implement the padding to the cache-line).
156 */
157template <typename T>
159 public:
160 /*
161 Default class constructor, will allocate a byte buffer with enough space to
162 store an instance of `std::atomic<T>` and paded to a multiple of the
163 processor cache-line size.
164
165 Will invoke `std::atomic<T>` inplace constructor using the allocated byte
166 array.
167 */
169 /*
170 Constructor that will assign the parameter value to the newly allocated
171 `std::atomic<T>`.
172
173 @param value The value to store in the underlying `std::atomic<T>` object.
174 */
176 /*
177 Deleted copy constructor, no copies allowed.
178 */
179 Aligned_atomic(Aligned_atomic<T> const &rhs) = delete;
180 /*
181 Move semantics constructor.
182
183 @param rhs The object to collect the underlying `std::atomic<T>` and byte
184 buffer from.
185 */
187 /*
188 Destructor that will invoke `std::atomi<T>` inplace destructor and release
189 the allocated byte buffer.
190 */
192
193 /*
194 Deleted copy operator.
195 */
197 /*
198 Move semantics operator.
199
200 @param rhs The object to collect the underlying `std::atomic<T>` and byte
201 buffer from.
202
203 @return This object reference, instantiated with the collected values.
204 */
206 /*
207 Assignment operator for parameter of templated type.
208
209 @param rhs The templated type value to be stored in the underlying
210 `std::atomic`.
211
212 @return This object reference, instantiated with the collected value.
213 */
215 /**
216 Casting operator for directly accessing the value of the underlying
217 `std::atomic<T>`.
218
219 @return The value of type `T` stored in the underlying `std::atomic`..
220 */
221 operator T() const;
222 /**
223 Equality operator to determine if the underlying storage memory is
224 initialized.
225
226 @param rhs nullptr value
227
228 @return true if the underlying storage memory is not initialized,
229 false otherwise.
230 */
231 bool operator==(std::nullptr_t rhs) const;
232 /**
233 Inequality operator to determine if the underlying storage memory is
234 initialized.
235
236 @param rhs nullptr value
237
238 @return true if the underlying storage memory is initialized, false
239 otherwise.
240 */
241 bool operator!=(std::nullptr_t rhs) const;
242 /**
243 Equality operator for determining if the value stored in the underlying
244 `std::atomic` equals the passed parameter.
245
246 @param rhs The value to compare with.
247
248 @return true if the parameter value equals the value stored in the
249 underlying `std::atomic`, false otherwise.
250 */
251 bool operator==(T rhs) const;
252 /**
253 Inequality operator for determining if the value stored in the underlying
254 `std::atomic` differs from the passed parameter.
255
256 @param rhs The value to compare with.
257
258 @return true if the parameter value differs from the value stored in the
259 underlying `std::atomic`, false otherwise.
260 */
261 bool operator!=(T rhs) const;
262 /*
263 Pointer operator that allows the access to the underlying `std::atomic<T>`
264 object.
265
266 @return The pointer to the underlying `std::atomic<T>` object.
267 */
268 std::atomic<T> *operator->();
269 /*
270 Pointer operator that allows the access to the underlying `std::atomic<T>`
271 object.
272
273 @return The const pointer to the underlying `std::atomic<T>` object.
274 */
275 const std::atomic<T> *operator->() const;
276 /*
277 Dereference operator that allows the access to the underlying
278 `std::atomic<T>` object.
279
280 @return The reference to the underlying `std::atomic<T>` object.
281 */
282 std::atomic<T> &operator*();
283 /*
284 Dereference operator that allows the access to the underlying
285 `std::atomic<T>` object.
286
287 @return The const reference to the underlying `std::atomic<T>` object.
288 */
289 const std::atomic<T> &operator*() const;
290 /*
291 The size of `std::atomic<T>`, as returned by `sizeof std::atomic<T>`.
292
293 @return The in-memory size of an `std::atomic<T>` instance.
294 */
295 size_t size() const;
296 /*
297 The size of the allocated byte buffer.
298
299 @return The in-memory size of the allocated byte buffer.
300 */
301 size_t allocated_size() const;
302
303 template <typename Accessor_type>
305
306 private:
307 /** The size of the byte buffer. */
308 size_t m_storage_size{0};
309 /** The byte buffer to use as underlying storage. */
310 void *m_storage{nullptr};
311 /** The pointer to the underlying `std::atomic<T>` object. */
312 std::atomic<T> *m_underlying{nullptr};
313};
314} // namespace memory
315
316template <typename T>
318 : m_storage_size{memory::minimum_cacheline_for<std::atomic<T>>()} {
320 m_underlying = new (this->m_storage) std::atomic<T>();
321}
322
323template <typename T>
325 : memory::Aligned_atomic<T>() {
326 this->m_underlying->store(value);
327}
328
329template <typename T>
331 if (this->m_underlying != nullptr) {
332 this->m_underlying->~atomic();
333 }
334 my_aligned_free(this->m_storage);
335 this->m_storage = rhs.m_storage;
336 this->m_storage_size = rhs.m_storage_size;
337 this->m_underlying = rhs.m_underlying;
338 rhs.m_storage = nullptr;
339 rhs.m_storage_size = 0;
340 rhs.m_underlying = nullptr;
341}
342
343template <typename T>
345 if (this->m_underlying != nullptr) {
346 this->m_underlying->~atomic();
347 }
348 my_aligned_free(this->m_storage);
349 this->m_storage = nullptr;
350 this->m_storage_size = 0;
351 this->m_underlying = nullptr;
352}
353
354template <typename T>
356 Aligned_atomic<T> &&rhs) {
357 if (this->m_underlying != nullptr) {
358 this->m_underlying->~atomic();
359 }
360 my_aligned_free(this->m_storage);
361 this->m_storage = rhs.m_storage;
362 this->m_storage_size = rhs.m_storage_size;
363 this->m_underlying = rhs.m_underlying;
364 rhs.m_storage = nullptr;
365 rhs.m_storage_size = 0;
366 rhs.m_underlying = nullptr;
367 return (*this);
368}
369
370template <typename T>
372 assert(this->m_underlying != nullptr);
373 this->m_underlying->store(rhs, std::memory_order_seq_cst);
374 return (*this);
375}
376
377template <typename T>
379 assert(this->m_underlying != nullptr);
380 return this->m_underlying->load(std::memory_order_relaxed);
381}
382
383template <typename T>
384bool memory::Aligned_atomic<T>::operator==(std::nullptr_t) const {
385 return this->m_underlying == nullptr;
386}
387
388template <typename T>
389bool memory::Aligned_atomic<T>::operator!=(std::nullptr_t) const {
390 return this->m_underlying != nullptr;
391}
392
393template <typename T>
395 if (this->m_underlying == nullptr) return false;
396 return this->m_underlying->load(std::memory_order_relaxed) == rhs;
397}
398
399template <typename T>
401 return !((*this) == rhs);
402}
403
404template <typename T>
406 assert(this->m_underlying != nullptr);
407 return this->m_underlying;
408}
409
410template <typename T>
411const std::atomic<T> *memory::Aligned_atomic<T>::operator->() const {
412 assert(this->m_underlying != nullptr);
413 return this->m_underlying;
414}
415
416template <typename T>
418 assert(this->m_underlying != nullptr);
419 return *this->m_underlying;
420}
421
422template <typename T>
423const std::atomic<T> &memory::Aligned_atomic<T>::operator*() const {
424 assert(this->m_underlying != nullptr);
425 return *this->m_underlying;
426}
427
428template <typename T>
430 return sizeof(std::atomic<T>);
431}
432
433template <typename T>
435 return this->m_storage_size;
436}
437
438#endif // MEMORY_ALIGNED_ATOMIC_H
Template that may access Aligned_atomic internals.
Definition: aligned_atomic.h:141
Templated class that encapsulates an std::atomic within a byte buffer that is padded to the processor...
Definition: aligned_atomic.h:158
Aligned_atomic< T > & operator=(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:330
size_t allocated_size() const
Definition: aligned_atomic.h:434
const std::atomic< T > * operator->() const
Definition: aligned_atomic.h:411
Aligned_atomic< T > & operator=(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:355
virtual ~Aligned_atomic()
Definition: aligned_atomic.h:344
bool operator!=(std::nullptr_t rhs) const
Inequality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:389
bool operator==(T rhs) const
Equality operator for determining if the value stored in the underlying std::atomic equals the passed...
Definition: aligned_atomic.h:394
std::atomic< T > * operator->()
Definition: aligned_atomic.h:405
Aligned_atomic(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic< T > & operator=(T rhs)
Definition: aligned_atomic.h:371
size_t size() const
Definition: aligned_atomic.h:429
Aligned_atomic()
Definition: aligned_atomic.h:317
std::atomic< T > & operator*()
Definition: aligned_atomic.h:417
size_t m_storage_size
The size of the byte buffer.
Definition: aligned_atomic.h:308
void * m_storage
The byte buffer to use as underlying storage.
Definition: aligned_atomic.h:310
bool operator==(std::nullptr_t rhs) const
Equality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:384
const std::atomic< T > & operator*() const
Definition: aligned_atomic.h:423
Aligned_atomic(T value)
Definition: aligned_atomic.h:324
std::atomic< T > * m_underlying
The pointer to the underlying std::atomic<T> object.
Definition: aligned_atomic.h:312
bool operator!=(T rhs) const
Inequality operator for determining if the value stored in the underlying std::atomic differs from th...
Definition: aligned_atomic.h:400
const char * p
Definition: ctype-mb.cc:1235
#define malloc(A)
Definition: lexyy.cc:914
#define free(A)
Definition: lexyy.cc:915
void * my_aligned_malloc(size_t size, size_t alignment)
Function allocates size bytes and returns a pointer to the allocated memory.
Definition: my_aligned_malloc.cc:38
void my_aligned_free(void *ptr)
Free allocated memory using my_aligned_malloc function.
Definition: my_aligned_malloc.cc:63
const std::string FILE("FILE")
std::unordered_map< meta::Metadata, Data_extension, meta::Metadata::Hash > Cache
Definition: cache.h:38
Definition: aligned_atomic.h:44
static size_t cache_line_size()
Definition: aligned_atomic.h:103
static size_t _cache_line_size()
Calculates and returns the size of the CPU cache line.
Definition: aligned_atomic.h:101
static size_t minimum_cacheline_for()
Retrieves the amount of bytes, multiple of the current cacheline size, needed to store an element of ...
Definition: aligned_atomic.h:134
static size_t _cacheline_for()
Retrieves the amount of bytes, multiple of the current cacheline size, needed to store an element of ...
Definition: aligned_atomic.h:117
size_t size(const char *const c)
Definition: base64.h:46
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:313
Definition: gcs_xcom_synode.h:64