MySQL 8.0.37
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, 0, 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 = 0;
64
65 GetLogicalProcessorInformation(0, &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/**
140 @class memory::Aligned_atomic
141
142 Templated class that encapsulates an `std::atomic` within a byte buffer that
143 is padded to the processor cache-line size.
144
145 This class purpose is to help prevent false sharing between atomically
146 accessed variables that are contiguous in memory. This is the normal case for
147 arrays or class members declared next to each other.
148
149 If the intended usage is none of the above, `std::atomic` class should be used
150 since the below implementation allocates more memory than needed for storing
151 the intended value (in order to implement the padding to the cache-line).
152 */
153template <typename T>
155 public:
156 /*
157 Default class constructor, will allocate a byte buffer with enough space to
158 store an instance of `std::atomic<T>` and paded to a multiple of the
159 processor cache-line size.
160
161 Will invoke `std::atomic<T>` inplace constructor using the allocated byte
162 array.
163 */
165 /*
166 Constructor that will assign the parameter value to the newly allocated
167 `std::atomic<T>`.
168
169 @param value The value to store in the underlying `std::atomic<T>` object.
170 */
172 /*
173 Deleted copy constructor, no copies allowed.
174 */
175 Aligned_atomic(Aligned_atomic<T> const &rhs) = delete;
176 /*
177 Move semantics constructor.
178
179 @param rhs The object to collect the underlying `std::atomic<T>` and byte
180 buffer from.
181 */
183 /*
184 Destructor that will invoke `std::atomi<T>` inplace destructor and release
185 the allocated byte buffer.
186 */
188
189 /*
190 Deleted copy operator.
191 */
193 /*
194 Move semantics operator.
195
196 @param rhs The object to collect the underlying `std::atomic<T>` and byte
197 buffer from.
198
199 @return This object reference, instantiated with the collected values.
200 */
202 /*
203 Assignment operator for parameter of templated type.
204
205 @param rhs The templated type value to be stored in the underlying
206 `std::atomic`.
207
208 @return This object reference, instantiated with the collected value.
209 */
211 /**
212 Casting operator for directly accessing the value of the underlying
213 `std::atomic<T>`.
214
215 @return The value of type `T` stored in the underlying `std::atomic`..
216 */
217 operator T() const;
218 /**
219 Equality operator to determine if the underlying storage memory is
220 initialized.
221
222 @param rhs nullptr value
223
224 @return true if the underlying storage memory is not initialized,
225 false otherwise.
226 */
227 bool operator==(std::nullptr_t rhs) const;
228 /**
229 Inequality operator to determine if the underlying storage memory is
230 initialized.
231
232 @param rhs nullptr value
233
234 @return true if the underlying storage memory is initialized, false
235 otherwise.
236 */
237 bool operator!=(std::nullptr_t rhs) const;
238 /**
239 Equality operator for determining if the value stored in the underlying
240 `std::atomic` equals the passed parameter.
241
242 @param rhs The value to compare with.
243
244 @return true if the parameter value equals the value stored in the
245 underlying `std::atomic`, false otherwise.
246 */
247 bool operator==(T rhs) const;
248 /**
249 Inequality operator for determining if the value stored in the underlying
250 `std::atomic` differs from the passed parameter.
251
252 @param rhs The value to compare with.
253
254 @return true if the parameter value differs from the value stored in the
255 underlying `std::atomic`, false otherwise.
256 */
257 bool operator!=(T rhs) const;
258 /*
259 Pointer operator that allows the access to the underlying `std::atomic<T>`
260 object.
261
262 @return The pointer to the underlying `std::atomic<T>` object.
263 */
264 std::atomic<T> *operator->();
265 /*
266 Pointer operator that allows the access to the underlying `std::atomic<T>`
267 object.
268
269 @return The const pointer to the underlying `std::atomic<T>` object.
270 */
271 const std::atomic<T> *operator->() const;
272 /*
273 Dereference operator that allows the access to the underlying
274 `std::atomic<T>` object.
275
276 @return The reference to the underlying `std::atomic<T>` object.
277 */
278 std::atomic<T> &operator*();
279 /*
280 Dereference operator that allows the access to the underlying
281 `std::atomic<T>` object.
282
283 @return The const reference to the underlying `std::atomic<T>` object.
284 */
285 const std::atomic<T> &operator*() const;
286 /*
287 The size of `std::atomic<T>`, as returned by `sizeof std::atomic<T>`.
288
289 @return The in-memory size of an `std::atomic<T>` instance.
290 */
291 size_t size() const;
292 /*
293 The size of the allocated byte buffer.
294
295 @return The in-memory size of the allocated byte buffer.
296 */
297 size_t allocated_size() const;
298
299 private:
300 /** The size of the byte buffer. */
301 size_t m_storage_size{0};
302 /** The byte buffer to use as underlying storage. */
303 void *m_storage{nullptr};
304 /** The pointer to the underlying `std::atomic<T>` object. */
305 std::atomic<T> *m_underlying{nullptr};
306};
307} // namespace memory
308
309template <typename T>
311 : m_storage_size{memory::minimum_cacheline_for<std::atomic<T>>()} {
313 m_underlying = new (this->m_storage) std::atomic<T>();
314}
315
316template <typename T>
318 : memory::Aligned_atomic<T>() {
319 this->m_underlying->store(value);
320}
321
322template <typename T>
324 if (this->m_underlying != nullptr) {
325 this->m_underlying->~atomic();
326 }
327 my_aligned_free(this->m_storage);
328 this->m_storage = rhs.m_storage;
329 this->m_storage_size = rhs.m_storage_size;
330 this->m_underlying = rhs.m_underlying;
331 rhs.m_storage = nullptr;
332 rhs.m_storage_size = 0;
333 rhs.m_underlying = nullptr;
334}
335
336template <typename T>
338 if (this->m_underlying != nullptr) {
339 this->m_underlying->~atomic();
340 }
341 my_aligned_free(this->m_storage);
342 this->m_storage = nullptr;
343 this->m_storage_size = 0;
344 this->m_underlying = nullptr;
345}
346
347template <typename T>
349 Aligned_atomic<T> &&rhs) {
350 if (this->m_underlying != nullptr) {
351 this->m_underlying->~atomic();
352 }
353 my_aligned_free(this->m_storage);
354 this->m_storage = rhs.m_storage;
355 this->m_storage_size = rhs.m_storage_size;
356 this->m_underlying = rhs.m_underlying;
357 rhs.m_storage = nullptr;
358 rhs.m_storage_size = 0;
359 rhs.m_underlying = nullptr;
360 return (*this);
361}
362
363template <typename T>
365 assert(this->m_underlying != nullptr);
366 this->m_underlying->store(rhs, std::memory_order_seq_cst);
367 return (*this);
368}
369
370template <typename T>
372 assert(this->m_underlying != nullptr);
373 return this->m_underlying->load(std::memory_order_relaxed);
374}
375
376template <typename T>
377bool memory::Aligned_atomic<T>::operator==(std::nullptr_t) const {
378 return this->m_underlying == nullptr;
379}
380
381template <typename T>
382bool memory::Aligned_atomic<T>::operator!=(std::nullptr_t) const {
383 return this->m_underlying != nullptr;
384}
385
386template <typename T>
388 if (this->m_underlying == nullptr) return false;
389 return this->m_underlying->load(std::memory_order_relaxed) == rhs;
390}
391
392template <typename T>
394 return !((*this) == rhs);
395}
396
397template <typename T>
399 assert(this->m_underlying != nullptr);
400 return this->m_underlying;
401}
402
403template <typename T>
404const std::atomic<T> *memory::Aligned_atomic<T>::operator->() const {
405 assert(this->m_underlying != nullptr);
406 return this->m_underlying;
407}
408
409template <typename T>
411 assert(this->m_underlying != nullptr);
412 return *this->m_underlying;
413}
414
415template <typename T>
416const std::atomic<T> &memory::Aligned_atomic<T>::operator*() const {
417 assert(this->m_underlying != nullptr);
418 return *this->m_underlying;
419}
420
421template <typename T>
423 return sizeof(std::atomic<T>);
424}
425
426template <typename T>
428 return this->m_storage_size;
429}
430
431#endif // MEMORY_ALIGNED_ATOMIC_H
Templated class that encapsulates an std::atomic within a byte buffer that is padded to the processor...
Definition: aligned_atomic.h:154
Aligned_atomic< T > & operator=(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:323
size_t allocated_size() const
Definition: aligned_atomic.h:427
const std::atomic< T > * operator->() const
Definition: aligned_atomic.h:404
Aligned_atomic< T > & operator=(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:348
virtual ~Aligned_atomic()
Definition: aligned_atomic.h:337
bool operator!=(std::nullptr_t rhs) const
Inequality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:382
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:387
std::atomic< T > * operator->()
Definition: aligned_atomic.h:398
Aligned_atomic(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic< T > & operator=(T rhs)
Definition: aligned_atomic.h:364
size_t size() const
Definition: aligned_atomic.h:422
Aligned_atomic()
Definition: aligned_atomic.h:310
std::atomic< T > & operator*()
Definition: aligned_atomic.h:410
size_t m_storage_size
The size of the byte buffer.
Definition: aligned_atomic.h:301
void * m_storage
The byte buffer to use as underlying storage.
Definition: aligned_atomic.h:303
bool operator==(std::nullptr_t rhs) const
Equality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:377
const std::atomic< T > & operator*() const
Definition: aligned_atomic.h:416
Aligned_atomic(T value)
Definition: aligned_atomic.h:317
std::atomic< T > * m_underlying
The pointer to the underlying std::atomic<T> object.
Definition: aligned_atomic.h:305
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:393
const char * p
Definition: ctype-mb.cc:1237
#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
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:420
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:315
Definition: gcs_xcom_synode.h:64