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
256 template <typename T> static Q_ALWAYS_INLINE
257 T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
258 {
259 // implement fetchAndSub on top of fetchAndAdd
260 return fetchAndAddRelaxed(_q_value, -operand);
261 }
262
263 template <typename T> static Q_ALWAYS_INLINE
264 T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
265 {
266 T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand);
267 BaseClass::acquireMemoryFence(_q_value);
268 return tmp;
269 }
270
271 template <typename T> static Q_ALWAYS_INLINE
272 T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
273 {
274 BaseClass::releaseMemoryFence(_q_value);
275 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
276 }
277
278 template <typename T> static Q_ALWAYS_INLINE
279 T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW
280 {
281 BaseClass::orderedMemoryFence(_q_value);
282 return BaseClass::fetchAndSubRelaxed(_q_value, operand);
283 }
284
285 template <typename T> static Q_ALWAYS_INLINE
286 T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
287 {
288 // implement fetchAndAnd on top of testAndSet
289 T tmp = BaseClass::load(_q_value);
290 Q_FOREVER {
291 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp & operand), &tmp))
292 return tmp;
293 }
294 }
295
296 template <typename T> static Q_ALWAYS_INLINE
297 T fetchAndAndAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
298 {
299 T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
300 BaseClass::acquireMemoryFence(_q_value);
301 return tmp;
302 }
303
304 template <typename T> static Q_ALWAYS_INLINE
305 T fetchAndAndRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
306 {
307 BaseClass::releaseMemoryFence(_q_value);
308 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
309 }
310
311 template <typename T> static Q_ALWAYS_INLINE
312 T fetchAndAndOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
313 {
314 BaseClass::orderedMemoryFence(_q_value);
315 return BaseClass::fetchAndAndRelaxed(_q_value, operand);
316 }
317
318 template <typename T> static Q_ALWAYS_INLINE
319 T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
320 {
321 // implement fetchAndOr on top of testAndSet
322 T tmp = BaseClass::load(_q_value);
323 Q_FOREVER {
324 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp | operand), &tmp))
325 return tmp;
326 }
327 }
328
329 template <typename T> static Q_ALWAYS_INLINE
330 T fetchAndOrAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
331 {
332 T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
333 BaseClass::acquireMemoryFence(_q_value);
334 return tmp;
335 }
336
337 template <typename T> static Q_ALWAYS_INLINE
338 T fetchAndOrRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
339 {
340 BaseClass::releaseMemoryFence(_q_value);
341 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
342 }
343
344 template <typename T> static Q_ALWAYS_INLINE
345 T fetchAndOrOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
346 {
347 BaseClass::orderedMemoryFence(_q_value);
348 return BaseClass::fetchAndOrRelaxed(_q_value, operand);
349 }
350
351 template <typename T> static Q_ALWAYS_INLINE
352 T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
353 {
354 // implement fetchAndXor on top of testAndSet
355 T tmp = BaseClass::load(_q_value);
356 Q_FOREVER {
357 if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp ^ operand), &tmp))
358 return tmp;
359 }
360 }
361
362 template <typename T> static Q_ALWAYS_INLINE
363 T fetchAndXorAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
364 {
365 T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
366 BaseClass::acquireMemoryFence(_q_value);
367 return tmp;
368 }
369
370 template <typename T> static Q_ALWAYS_INLINE
371 T fetchAndXorRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
372 {
373 BaseClass::releaseMemoryFence(_q_value);
374 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
375 }
376
377 template <typename T> static Q_ALWAYS_INLINE
378 T fetchAndXorOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
379 {
380 BaseClass::orderedMemoryFence(_q_value);
381 return BaseClass::fetchAndXorRelaxed(_q_value, operand);
382 }
383};
384
385QT_END_NAMESPACE
386#endif // QGENERICATOMIC_H
387