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