1/****************************************************************************
2**
3** Copyright (C) 2011 Thiago Macieira <thiago@kde.org>
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QGENERICATOMIC_H
42#define QGENERICATOMIC_H
43
44#include <QtCore/qglobal.h>
45#include <QtCore/qtypeinfo.h>
46
47QT_BEGIN_NAMESPACE
48
49#if 0
50// silence syncqt warnings
51QT_END_NAMESPACE
52#pragma qt_sync_skip_header_check
53#pragma qt_sync_stop_processing
54#endif
55
56template<int> struct QAtomicOpsSupport { enum { IsSupported = 0 }; };
57template<> struct QAtomicOpsSupport<4> { enum { IsSupported = 1 }; };
58
59template <typename T> struct QAtomicAdditiveType
60{
61 typedef T AdditiveT;
62 static const int AddScale = 1;
63};
64template <typename T> struct QAtomicAdditiveType<T *>
65{
66 typedef qptrdiff AdditiveT;
67 static const int AddScale = sizeof(T);
68};
69
70// not really atomic...
71template <typename BaseClass> struct QGenericAtomicOps
72{
73 template <typename T> struct AtomicType { typedef T Type; typedef T *PointerType; };
74
75 template <typename T> static void acquireMemoryFence(const T &_q_value) noexcept
76 {
77 BaseClass::orderedMemoryFence(_q_value);
78 }
79 template <typename T> static void releaseMemoryFence(const T &_q_value) noexcept
80 {
81 BaseClass::orderedMemoryFence(_q_value);
82 }
83 template <typename T> static void orderedMemoryFence(const T &) noexcept
84 {
85 }
86
87 template <typename T> static Q_ALWAYS_INLINE
88 T load(const T &_q_value) noexcept
89 {
90 return _q_value;
91 }
92
93 template <typename T, typename X> static Q_ALWAYS_INLINE
94 void store(T &_q_value, X newValue) noexcept
95 {
96 _q_value = newValue;
97 }
98
99 template <typename T> static Q_ALWAYS_INLINE
100 T loadRelaxed(const T &_q_value) noexcept
101 {
102 return _q_value;
103 }
104
105 template <typename T, typename X> static Q_ALWAYS_INLINE
106 void storeRelaxed(T &_q_value, X newValue) noexcept
107 {
108 _q_value = newValue;
109 }
110
111 template <typename T> static Q_ALWAYS_INLINE
112 T loadAcquire(const T &_q_value) noexcept
113 {
114 T tmp = *static_cast<const volatile T *>(&_q_value);
115 BaseClass::acquireMemoryFence(_q_value);
116 return tmp;
117 }
118
119 template <typename T, typename X> static Q_ALWAYS_INLINE
120 void storeRelease(T &_q_value, X newValue) noexcept
121 {
122 BaseClass::releaseMemoryFence(_q_value);
123 *static_cast<volatile T *>(&_q_value) = newValue;
124 }
125
126 static inline constexpr bool isReferenceCountingNative() noexcept
127 { return BaseClass::isFetchAndAddNative(); }
128 static inline constexpr bool isReferenceCountingWaitFree() noexcept
129 { return BaseClass::isFetchAndAddWaitFree(); }
130 template <typename T> static Q_ALWAYS_INLINE
131 bool ref(T &_q_value) noexcept
132 {
133 return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1);
134 }
135
136 template <typename T> static Q_ALWAYS_INLINE
137 bool deref(T &_q_value) noexcept
138 {
139 return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1;
140 }
141
142#if 0
143 // These functions have no default implementation
144 // Archictectures must implement them
145 static inline constexpr bool isTestAndSetNative() noexcept;
146 static inline constexpr bool isTestAndSetWaitFree() noexcept;
147 template <typename T, typename X> static inline
148 bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue) noexcept;
149 template <typename T, typename X> static inline
150 bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept;
151#endif
152
153 template <typename T, typename X> static Q_ALWAYS_INLINE
154 bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue) noexcept
155 {
156 bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
157 BaseClass::acquireMemoryFence(_q_value);
158 return tmp;
159 }
160
161 template <typename T, typename X> static Q_ALWAYS_INLINE
162 bool testAndSetRelease(T &_q_value, X expectedValue, X newValue) noexcept
163 {
164 BaseClass::releaseMemoryFence(_q_value);
165 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
166 }
167
168 template <typename T, typename X> static Q_ALWAYS_INLINE
169 bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue) noexcept
170 {
171 BaseClass::orderedMemoryFence(_q_value);
172 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
173 }
174
175 template <typename T, typename X> static Q_ALWAYS_INLINE
176 bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
177 {
178 bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
179 BaseClass::acquireMemoryFence(_q_value);
180 return tmp;
181 }
182
183 template <typename T, typename X> static Q_ALWAYS_INLINE
184 bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
185 {
186 BaseClass::releaseMemoryFence(_q_value);
187 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
188 }
189
190 template <typename T, typename X> static Q_ALWAYS_INLINE
191 bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
192 {
193 BaseClass::orderedMemoryFence(_q_value);
194 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
195 }
196
197 static inline constexpr bool isFetchAndStoreNative() noexcept { return false; }
198 static inline constexpr bool isFetchAndStoreWaitFree() noexcept { return false; }
199
200 template <typename T, typename X> static Q_ALWAYS_INLINE
201 T fetchAndStoreRelaxed(T &_q_value, X newValue) noexcept
202 {
203 // implement fetchAndStore on top of testAndSet
204 Q_FOREVER {
205 T tmp = loadRelaxed(_q_value);
206 if (BaseClass::testAndSetRelaxed(_q_value, tmp, newValue))
207 return tmp;
208 }
209 }
210
211 template <typename T, typename X> static Q_ALWAYS_INLINE
212 T fetchAndStoreAcquire(T &_q_value, X newValue) noexcept
213 {
214 T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
215 BaseClass::acquireMemoryFence(_q_value);
216 return tmp;
217 }
218
219 template <typename T, typename X> static Q_ALWAYS_INLINE
220 T fetchAndStoreRelease(T &_q_value, X newValue) noexcept
221 {
222 BaseClass::releaseMemoryFence(_q_value);
223 return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
224 }
225
226 template <typename T, typename X> static Q_ALWAYS_INLINE
227 T fetchAndStoreOrdered(T &_q_value, X newValue) noexcept
228 {
229 BaseClass::orderedMemoryFence(_q_value);
230 return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
231 }
232
233 static inline constexpr bool isFetchAndAddNative() noexcept { return false; }
234 static inline constexpr bool isFetchAndAddWaitFree() noexcept { return false; }
235 template <typename T> static Q_ALWAYS_INLINE
236 T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
237 {
238 // implement fetchAndAdd on top of testAndSet
239 Q_FOREVER {
240 T tmp = BaseClass::loadRelaxed(_q_value);
241 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp + valueToAdd)))
242 return tmp;
243 }
244 }
245
246 template <typename T> static Q_ALWAYS_INLINE
247 T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
248 {
249 T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
250 BaseClass::acquireMemoryFence(_q_value);
251 return tmp;
252 }
253
254 template <typename T> static Q_ALWAYS_INLINE
255 T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
256 {
257 BaseClass::releaseMemoryFence(_q_value);
258 return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
259 }
260
261 template <typename T> static Q_ALWAYS_INLINE
262 T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
263 {
264 BaseClass::orderedMemoryFence(_q_value);
265 return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
266 }
267
268QT_WARNING_PUSH
269QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
270 template <typename T> static Q_ALWAYS_INLINE
271 T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
272 {
273 // implement fetchAndSub on top of fetchAndAdd
274 return fetchAndAddRelaxed(_q_value, -operand);
275 }
276QT_WARNING_POP
277
278 template <typename T> static Q_ALWAYS_INLINE
279 T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
280 {
281 T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand);
282 BaseClass::acquireMemoryFence(_q_value);
283 return tmp;
284 }
285
286 template <typename T> static Q_ALWAYS_INLINE
287 T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
288 {
289 BaseClass::releaseMemoryFence(_q_value);
290 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
291 }
292
293 template <typename T> static Q_ALWAYS_INLINE
294 T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
295 {
296 BaseClass::orderedMemoryFence(_q_value);
297 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
298 }
299
300 template <typename T> static Q_ALWAYS_INLINE
301 T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
302 {
303 // implement fetchAndAnd on top of testAndSet
304 T tmp = BaseClass::loadRelaxed(_q_value);
305 Q_FOREVER {
306 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp & operand), &tmp))
307 return tmp;
308 }
309 }
310
311 template <typename T> static Q_ALWAYS_INLINE
312 T fetchAndAndAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
313 {
314 T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
315 BaseClass::acquireMemoryFence(_q_value);
316 return tmp;
317 }
318
319 template <typename T> static Q_ALWAYS_INLINE
320 T fetchAndAndRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
321 {
322 BaseClass::releaseMemoryFence(_q_value);
323 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
324 }
325
326 template <typename T> static Q_ALWAYS_INLINE
327 T fetchAndAndOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
328 {
329 BaseClass::orderedMemoryFence(_q_value);
330 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
331 }
332
333 template <typename T> static Q_ALWAYS_INLINE
334 T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
335 {
336 // implement fetchAndOr on top of testAndSet
337 T tmp = BaseClass::loadRelaxed(_q_value);
338 Q_FOREVER {
339 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp | operand), &tmp))
340 return tmp;
341 }
342 }
343
344 template <typename T> static Q_ALWAYS_INLINE
345 T fetchAndOrAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
346 {
347 T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
348 BaseClass::acquireMemoryFence(_q_value);
349 return tmp;
350 }
351
352 template <typename T> static Q_ALWAYS_INLINE
353 T fetchAndOrRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
354 {
355 BaseClass::releaseMemoryFence(_q_value);
356 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
357 }
358
359 template <typename T> static Q_ALWAYS_INLINE
360 T fetchAndOrOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
361 {
362 BaseClass::orderedMemoryFence(_q_value);
363 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
364 }
365
366 template <typename T> static Q_ALWAYS_INLINE
367 T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
368 {
369 // implement fetchAndXor on top of testAndSet
370 T tmp = BaseClass::loadRelaxed(_q_value);
371 Q_FOREVER {
372 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp ^ operand), &tmp))
373 return tmp;
374 }
375 }
376
377 template <typename T> static Q_ALWAYS_INLINE
378 T fetchAndXorAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
379 {
380 T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
381 BaseClass::acquireMemoryFence(_q_value);
382 return tmp;
383 }
384
385 template <typename T> static Q_ALWAYS_INLINE
386 T fetchAndXorRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
387 {
388 BaseClass::releaseMemoryFence(_q_value);
389 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
390 }
391
392 template <typename T> static Q_ALWAYS_INLINE
393 T fetchAndXorOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept
394 {
395 BaseClass::orderedMemoryFence(_q_value);
396 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
397 }
398};
399
400QT_END_NAMESPACE
401#endif // QGENERICATOMIC_H
402