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 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | #if 0 |
50 | // silence syncqt warnings |
51 | QT_END_NAMESPACE |
52 | #pragma qt_sync_skip_header_check |
53 | #pragma qt_sync_stop_processing |
54 | #endif |
55 | |
56 | template<int> struct QAtomicOpsSupport { enum { IsSupported = 0 }; }; |
57 | template<> struct QAtomicOpsSupport<4> { enum { IsSupported = 1 }; }; |
58 | |
59 | template <typename T> struct QAtomicAdditiveType |
60 | { |
61 | typedef T AdditiveT; |
62 | static const int AddScale = 1; |
63 | }; |
64 | template <typename T> struct QAtomicAdditiveType<T *> |
65 | { |
66 | typedef qptrdiff AdditiveT; |
67 | static const int AddScale = sizeof(T); |
68 | }; |
69 | |
70 | // not really atomic... |
71 | template <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 Q_DECL_CONSTEXPR bool isReferenceCountingNative() noexcept |
127 | { return BaseClass::isFetchAndAddNative(); } |
128 | static inline Q_DECL_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 Q_DECL_CONSTEXPR bool isTestAndSetNative() noexcept; |
146 | static inline Q_DECL_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 Q_DECL_CONSTEXPR bool isFetchAndStoreNative() noexcept { return false; } |
198 | static inline Q_DECL_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 Q_DECL_CONSTEXPR bool isFetchAndAddNative() noexcept { return false; } |
234 | static inline Q_DECL_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 | |
268 | QT_WARNING_PUSH |
269 | QT_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 | } |
276 | QT_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 | |
400 | QT_END_NAMESPACE |
401 | #endif // QGENERICATOMIC_H |
402 | |