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