1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
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#include <QtCore/qglobal.h>
42
43#ifndef QATOMIC_H
44#define QATOMIC_H
45
46#include <QtCore/qbasicatomic.h>
47
48QT_BEGIN_NAMESPACE
49
50QT_WARNING_PUSH
51QT_WARNING_DISABLE_GCC("-Wextra")
52
53// High-level atomic integer operations
54template <typename T>
55class QAtomicInteger : public QBasicAtomicInteger<T>
56{
57public:
58 // Non-atomic API
59#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
60 constexpr QAtomicInteger(T value = 0) Q_DECL_NOTHROW : QBasicAtomicInteger<T>(value) {}
61#else
62 inline QAtomicInteger(T value = 0) Q_DECL_NOTHROW
63 {
64 this->_q_value = value;
65 }
66#endif
67
68 inline QAtomicInteger(const QAtomicInteger &other) Q_DECL_NOTHROW
69#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
70 : QBasicAtomicInteger<T>()
71#endif
72 {
73 this->storeRelease(other.loadAcquire());
74 }
75
76 inline QAtomicInteger &operator=(const QAtomicInteger &other) Q_DECL_NOTHROW
77 {
78 this->storeRelease(other.loadAcquire());
79 return *this;
80 }
81
82#ifdef Q_CLANG_QDOC
83 T load() const;
84 T loadAcquire() const;
85 void store(T newValue);
86 void storeRelease(T newValue);
87
88 operator T() const;
89 QAtomicInteger &operator=(T);
90
91 static Q_DECL_CONSTEXPR bool isReferenceCountingNative();
92 static Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree();
93
94 bool ref();
95 bool deref();
96
97 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
98 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
99
100 bool testAndSetRelaxed(T expectedValue, T newValue);
101 bool testAndSetAcquire(T expectedValue, T newValue);
102 bool testAndSetRelease(T expectedValue, T newValue);
103 bool testAndSetOrdered(T expectedValue, T newValue);
104
105 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
106 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
107
108 T fetchAndStoreRelaxed(T newValue);
109 T fetchAndStoreAcquire(T newValue);
110 T fetchAndStoreRelease(T newValue);
111 T fetchAndStoreOrdered(T newValue);
112
113 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
114 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
115
116 T fetchAndAddRelaxed(T valueToAdd);
117 T fetchAndAddAcquire(T valueToAdd);
118 T fetchAndAddRelease(T valueToAdd);
119 T fetchAndAddOrdered(T valueToAdd);
120
121 T fetchAndSubRelaxed(T valueToSub);
122 T fetchAndSubAcquire(T valueToSub);
123 T fetchAndSubRelease(T valueToSub);
124 T fetchAndSubOrdered(T valueToSub);
125
126 T fetchAndOrRelaxed(T valueToOr);
127 T fetchAndOrAcquire(T valueToOr);
128 T fetchAndOrRelease(T valueToOr);
129 T fetchAndOrOrdered(T valueToOr);
130
131 T fetchAndAndRelaxed(T valueToAnd);
132 T fetchAndAndAcquire(T valueToAnd);
133 T fetchAndAndRelease(T valueToAnd);
134 T fetchAndAndOrdered(T valueToAnd);
135
136 T fetchAndXorRelaxed(T valueToXor);
137 T fetchAndXorAcquire(T valueToXor);
138 T fetchAndXorRelease(T valueToXor);
139 T fetchAndXorOrdered(T valueToXor);
140
141 T operator++();
142 T operator++(int);
143 T operator--();
144 T operator--(int);
145 T operator+=(T value);
146 T operator-=(T value);
147 T operator|=(T value);
148 T operator&=(T value);
149 T operator^=(T value);
150#endif
151};
152
153class QAtomicInt : public QAtomicInteger<int>
154{
155public:
156 // Non-atomic API
157 // We could use QT_COMPILER_INHERITING_CONSTRUCTORS, but we need only one;
158 // the implicit definition for all the others is fine.
159#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
160 constexpr
161#endif
162 QAtomicInt(int value = 0) Q_DECL_NOTHROW : QAtomicInteger<int>(value) {}
163};
164
165// High-level atomic pointer operations
166template <typename T>
167class QAtomicPointer : public QBasicAtomicPointer<T>
168{
169public:
170#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
171 constexpr QAtomicPointer(T *value = nullptr) Q_DECL_NOTHROW : QBasicAtomicPointer<T>(value) {}
172#else
173 inline QAtomicPointer(T *value = nullptr) Q_DECL_NOTHROW
174 {
175 this->store(value);
176 }
177#endif
178 inline QAtomicPointer(const QAtomicPointer<T> &other) Q_DECL_NOTHROW
179#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
180 : QBasicAtomicPointer<T>()
181#endif
182 {
183 this->storeRelease(other.loadAcquire());
184 }
185
186 inline QAtomicPointer<T> &operator=(const QAtomicPointer<T> &other) Q_DECL_NOTHROW
187 {
188 this->storeRelease(other.loadAcquire());
189 return *this;
190 }
191
192#ifdef Q_QDOC
193 T *load() const;
194 T *loadAcquire() const;
195 void store(T *newValue);
196 void storeRelease(T *newValue);
197
198 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
199 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
200
201 bool testAndSetRelaxed(T *expectedValue, T *newValue);
202 bool testAndSetAcquire(T *expectedValue, T *newValue);
203 bool testAndSetRelease(T *expectedValue, T *newValue);
204 bool testAndSetOrdered(T *expectedValue, T *newValue);
205
206 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
207 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
208
209 T *fetchAndStoreRelaxed(T *newValue);
210 T *fetchAndStoreAcquire(T *newValue);
211 T *fetchAndStoreRelease(T *newValue);
212 T *fetchAndStoreOrdered(T *newValue);
213
214 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
215 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
216
217 T *fetchAndAddRelaxed(qptrdiff valueToAdd);
218 T *fetchAndAddAcquire(qptrdiff valueToAdd);
219 T *fetchAndAddRelease(qptrdiff valueToAdd);
220 T *fetchAndAddOrdered(qptrdiff valueToAdd);
221#endif
222};
223
224QT_WARNING_POP
225
226#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
227# undef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
228#endif
229
230/*!
231 This is a helper for the assignment operators of implicitly
232 shared classes. Your assignment operator should look like this:
233
234 \snippet code/src.corelib.thread.qatomic.h 0
235*/
236template <typename T>
237inline void qAtomicAssign(T *&d, T *x)
238{
239 if (d == x)
240 return;
241 x->ref.ref();
242 if (!d->ref.deref())
243 delete d;
244 d = x;
245}
246
247/*!
248 This is a helper for the detach method of implicitly shared
249 classes. Your private class needs a copy constructor which copies
250 the members and sets the refcount to 1. After that, your detach
251 function should look like this:
252
253 \snippet code/src.corelib.thread.qatomic.h 1
254*/
255template <typename T>
256inline void qAtomicDetach(T *&d)
257{
258 if (d->ref.load() == 1)
259 return;
260 T *x = d;
261 d = new T(*d);
262 if (!x->ref.deref())
263 delete x;
264}
265
266QT_END_NAMESPACE
267#endif // QATOMIC_H
268