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) Q_DECL_NOTHROW
76 {
77 BaseClass::orderedMemoryFence(_q_value);
78 }
79 template <typename T> static void releaseMemoryFence(const T &_q_value) Q_DECL_NOTHROW
80 {
81 BaseClass::orderedMemoryFence(_q_value);
82 }
83 template <typename T> static void orderedMemoryFence(const T &) Q_DECL_NOTHROW
84 {
85 }
86
87 template <typename T> static Q_ALWAYS_INLINE
88 T load(const T &_q_value) Q_DECL_NOTHROW
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) Q_DECL_NOTHROW
95 {
96 _q_value = newValue;
97 }
98
99 template <typename T> static Q_ALWAYS_INLINE
100 T loadAcquire(const T &_q_value) Q_DECL_NOTHROW
101 {
102 T tmp = *static_cast<const volatile T *>(&_q_value);
103 BaseClass::acquireMemoryFence(_q_value);
104 return tmp;
105 }
106
107 template <typename T, typename X> static Q_ALWAYS_INLINE
108 void storeRelease(T &_q_value, X newValue) Q_DECL_NOTHROW
109 {
110 BaseClass::releaseMemoryFence(_q_value);
111 *static_cast<volatile T *>(&_q_value) = newValue;
112 }
113
114 static inline Q_DECL_CONSTEXPR bool isReferenceCountingNative() Q_DECL_NOTHROW
115 { return BaseClass::isFetchAndAddNative(); }
116 static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW
117 { return BaseClass::isFetchAndAddWaitFree(); }
118 template <typename T> static Q_ALWAYS_INLINE
119 bool ref(T &_q_value) Q_DECL_NOTHROW
120 {
121 return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1);
122 }
123
124 template <typename T> static Q_ALWAYS_INLINE
125 bool deref(T &_q_value) Q_DECL_NOTHROW
126 {
127 return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1;
128 }
129
130#if 0
131 // These functions have no default implementation
132 // Archictectures must implement them
133 static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW;
134 static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW;
135 template <typename T, typename X> static inline
136 bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW;
137 template <typename T, typename X> static inline
138 bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW;
139#endif
140
141 template <typename T, typename X> static Q_ALWAYS_INLINE
142 bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW
143 {
144 bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
145 BaseClass::acquireMemoryFence(_q_value);
146 return tmp;
147 }
148
149 template <typename T, typename X> static Q_ALWAYS_INLINE
150 bool testAndSetRelease(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW
151 {
152 BaseClass::releaseMemoryFence(_q_value);
153 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
154 }
155
156 template <typename T, typename X> static Q_ALWAYS_INLINE
157 bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW
158 {
159 BaseClass::orderedMemoryFence(_q_value);
160 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
161 }
162
163 template <typename T, typename X> static Q_ALWAYS_INLINE
164 bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW
165 {
166 bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
167 BaseClass::acquireMemoryFence(_q_value);
168 return tmp;
169 }
170
171 template <typename T, typename X> static Q_ALWAYS_INLINE
172 bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW
173 {
174 BaseClass::releaseMemoryFence(_q_value);
175 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
176 }
177
178 template <typename T, typename X> static Q_ALWAYS_INLINE
179 bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW
180 {
181 BaseClass::orderedMemoryFence(_q_value);
182 return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
183 }
184
185 static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return false; }
186 static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return false; }
187
188 template <typename T, typename X> static Q_ALWAYS_INLINE
189 T fetchAndStoreRelaxed(T &_q_value, X newValue) Q_DECL_NOTHROW
190 {
191 // implement fetchAndStore on top of testAndSet
192 Q_FOREVER {
193 T tmp = load(_q_value);
194 if (BaseClass::testAndSetRelaxed(_q_value, tmp, newValue))
195 return tmp;
196 }
197 }
198
199 template <typename T, typename X> static Q_ALWAYS_INLINE
200 T fetchAndStoreAcquire(T &_q_value, X newValue) Q_DECL_NOTHROW
201 {
202 T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
203 BaseClass::acquireMemoryFence(_q_value);
204 return tmp;
205 }
206
207 template <typename T, typename X> static Q_ALWAYS_INLINE
208 T fetchAndStoreRelease(T &_q_value, X newValue) Q_DECL_NOTHROW
209 {
210 BaseClass::releaseMemoryFence(_q_value);
211 return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
212 }
213
214 template <typename T, typename X> static Q_ALWAYS_INLINE
215 T fetchAndStoreOrdered(T &_q_value, X newValue) Q_DECL_NOTHROW
216 {
217 BaseClass::orderedMemoryFence(_q_value);
218 return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
219 }
220
221 static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return false; }
222 static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return false; }
223 template <typename T> static Q_ALWAYS_INLINE
224 T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
225 {
226 // implement fetchAndAdd on top of testAndSet
227 Q_FOREVER {
228 T tmp = BaseClass::load(_q_value);
229 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp + valueToAdd)))
230 return tmp;
231 }
232 }
233
234 template <typename T> static Q_ALWAYS_INLINE
235 T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
236 {
237 T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
238 BaseClass::acquireMemoryFence(_q_value);
239 return tmp;
240 }
241
242 template <typename T> static Q_ALWAYS_INLINE
243 T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
244 {
245 BaseClass::releaseMemoryFence(_q_value);
246 return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
247 }
248
249 template <typename T> static Q_ALWAYS_INLINE
250 T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
251 {
252 BaseClass::orderedMemoryFence(_q_value);
253 return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
254 }
255
256QT_WARNING_PUSH
257QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
258 template <typename T> static Q_ALWAYS_INLINE
259 T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
260 {
261 // implement fetchAndSub on top of fetchAndAdd
262 return fetchAndAddRelaxed(_q_value, -operand);
263 }
264QT_WARNING_POP
265
266 template <typename T> static Q_ALWAYS_INLINE
267 T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
268 {
269 T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand);
270 BaseClass::acquireMemoryFence(_q_value);
271 return tmp;
272 }
273
274 template <typename T> static Q_ALWAYS_INLINE
275 T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
276 {
277 BaseClass::releaseMemoryFence(_q_value);
278 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
279 }
280
281 template <typename T> static Q_ALWAYS_INLINE
282 T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
283 {
284 BaseClass::orderedMemoryFence(_q_value);
285 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
286 }
287
288 template <typename T> static Q_ALWAYS_INLINE
289 T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
290 {
291 // implement fetchAndAnd on top of testAndSet
292 T tmp = BaseClass::load(_q_value);
293 Q_FOREVER {
294 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp & operand), &tmp))
295 return tmp;
296 }
297 }
298
299 template <typename T> static Q_ALWAYS_INLINE
300 T fetchAndAndAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
301 {
302 T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
303 BaseClass::acquireMemoryFence(_q_value);
304 return tmp;
305 }
306
307 template <typename T> static Q_ALWAYS_INLINE
308 T fetchAndAndRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
309 {
310 BaseClass::releaseMemoryFence(_q_value);
311 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
312 }
313
314 template <typename T> static Q_ALWAYS_INLINE
315 T fetchAndAndOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
316 {
317 BaseClass::orderedMemoryFence(_q_value);
318 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
319 }
320
321 template <typename T> static Q_ALWAYS_INLINE
322 T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
323 {
324 // implement fetchAndOr on top of testAndSet
325 T tmp = BaseClass::load(_q_value);
326 Q_FOREVER {
327 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp | operand), &tmp))
328 return tmp;
329 }
330 }
331
332 template <typename T> static Q_ALWAYS_INLINE
333 T fetchAndOrAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
334 {
335 T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
336 BaseClass::acquireMemoryFence(_q_value);
337 return tmp;
338 }
339
340 template <typename T> static Q_ALWAYS_INLINE
341 T fetchAndOrRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
342 {
343 BaseClass::releaseMemoryFence(_q_value);
344 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
345 }
346
347 template <typename T> static Q_ALWAYS_INLINE
348 T fetchAndOrOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
349 {
350 BaseClass::orderedMemoryFence(_q_value);
351 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
352 }
353
354 template <typename T> static Q_ALWAYS_INLINE
355 T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
356 {
357 // implement fetchAndXor on top of testAndSet
358 T tmp = BaseClass::load(_q_value);
359 Q_FOREVER {
360 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp ^ operand), &tmp))
361 return tmp;
362 }
363 }
364
365 template <typename T> static Q_ALWAYS_INLINE
366 T fetchAndXorAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
367 {
368 T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
369 BaseClass::acquireMemoryFence(_q_value);
370 return tmp;
371 }
372
373 template <typename T> static Q_ALWAYS_INLINE
374 T fetchAndXorRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
375 {
376 BaseClass::releaseMemoryFence(_q_value);
377 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
378 }
379
380 template <typename T> static Q_ALWAYS_INLINE
381 T fetchAndXorOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
382 {
383 BaseClass::orderedMemoryFence(_q_value);
384 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
385 }
386};
387
388QT_END_NAMESPACE
389#endif // QGENERICATOMIC_H
390